Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-6x26-6r6f-m537

Опубликовано: 31 июл. 2026
Источник: github
Github: Прошло ревью
CVSS3: 8.2

Описание

Thumbor treats ALLOWED_SOURCES string patterns as unescaped regex, allowing hostname bypass via wildcard dot

Summary

The ALLOWED_SOURCES configuration is meant to restrict which hosts Thumbor's HTTP loader may fetch images from. Plain-string entries in that list (the overwhelming majority of real-world and documented configurations) are passed directly to re.match() without escaping. Because . is a regex wildcard, every dot in a domain name becomes a bypass vector: s.glbimg.com silently matches sXglbimgYcom, sAglbimg.com, and any other hostname that differs only at a dot position. This undermines the primary SSRF defence that ALLOWED_SOURCES is intended to provide.

Affected component

thumbor/loaders/http_loader.pyvalidate()

Proof of concept

import re from thumbor.config import Config from thumbor.context import Context from thumbor.loaders import http_loader as loader config = Config() config.ALLOWED_SOURCES = ["s.glbimg.com"] # typical user config ctx = Context(None, config, None) # These should be blocked — both return True due to the unescaped dot print(loader.validate(ctx, "http://sXglbimgYcom/secret.jpg")) # True ← bypass print(loader.validate(ctx, "http://sAglbimg.com/secret.jpg")) # True ← bypass # Legitimate origin — correctly allowed print(loader.validate(ctx, "http://s.glbimg.com/logo.jpg")) # True ← correct

Root cause

thumbor/loaders/http_loader.py (before fix):

for pattern in context.config.ALLOWED_SOURCES: if isinstance(pattern, Pattern): match = url else: pattern = f"^{pattern}$" # <-- dots not escaped, act as regex wildcard match = res.hostname if re.match(pattern, match): return True

Impact

An attacker who can influence the image source URL passed to Thumbor can fetch images from arbitrary hosts, bypassing the ALLOWED_SOURCES allowlist.

Preconditions:

  • ALLOWED_SOURCES contains at least one plain-string entry (the common case; all official documentation examples use plain strings).
  • The attacker can supply or influence the image URL — true whenever ALLOW_UNSAFE_URL = True (the default), or when the application forwards user input to a signed URL endpoint.

Fix

Apply re.escape() to plain-string patterns before compiling them, so every character is matched literally:

else: pattern = f"^{re.escape(pattern)}$" # dots and other metacharacters are now literal match = res.hostname

This is a one-call addition with no breaking change for correctly written configurations. Users who need real regular-expression behaviour should supply a compiled pattern (re.compile(r"s\.glbimg\.com")), which is already handled by the existing isinstance(pattern, Pattern) branch and is unaffected by this change.

The ALLOWED_SOURCES docstring in config.py was also updated to document the two-mode behaviour explicitly.

Пакеты

Наименование

thumbor

pip
Затронутые версииВерсия исправления

<= 7.7.7

7.8.0

EPSS

Процентиль: 21%
0.00287
Низкий

8.2 High

CVSS3

Дефекты

CWE-1333

Связанные уязвимости

CVSS3: 8.2
ubuntu
8 дней назад

Thumbor is an open-source photo thumbnail service by globo.com. Prior to 7.8.0, the ALLOWED_SOURCES configuration passes plain strings to re.match() without escaping dots, so a hostname differing at dot positions can match the allowlist. This issue is fixed in 7.8.0.

CVSS3: 8.2
nvd
8 дней назад

Thumbor is an open-source photo thumbnail service by globo.com. Prior to 7.8.0, the ALLOWED_SOURCES configuration passes plain strings to re.match() without escaping dots, so a hostname differing at dot positions can match the allowlist. This issue is fixed in 7.8.0.

CVSS3: 8.2
debian
8 дней назад

Thumbor is an open-source photo thumbnail service by globo.com. Prior ...

EPSS

Процентиль: 21%
0.00287
Низкий

8.2 High

CVSS3

Дефекты

CWE-1333