Answer in brief
CVE-2026-53500 records a High severity (CVSS 8.2) vulnerability in Thumbor treats ALLOWED_SOURCES string patterns as unescaped regex, allowing hostname bypass via wildcard dot. The current sources do not mark it as known exploited. The current feed maps thumbor (pip). Check affected ranges and fixed versions before updating.
Analysis pending evidence review
HOL Guard separates source facts from reviewed analysis. See the methodology.
CVSS is 8.2. The current sources do not mark it as known exploited. Treat this as a source-backed prioritization signal, not a statement about your environment.
Analysis status
Analysis pending evidence review
Factual feed record only; HOL analysis is not approved for indexing. Read the methodology.
The current feed maps thumbor (pip). Check affected ranges and fixed versions before updating.
| Package | Affected range | Fixed version |
|---|---|---|
| thumborpip | <=7.7.7 | 7.8.0 |
Published upstream
Jul 31, 2026
Evidence: source:ghsa:source_dates:source-dates:recordSource modified
Sep 30, 2026
Evidence: source:ghsa:source_dates:source-dates:recordFirst seen by HOL
Aug 2, 2026
## 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.py` — `validate()` ## Proof of concept ```python 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): ```python 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: ```python 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.
Quoted source text, attributed separately from HOL analysis.