Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Network-reachable via /unsafe/ path with no authentication when ALLOW_UNSAFE_URL=True; sole impact is availability via resource exhaustion, no C or I impact.
Primary rating from Vendor (https://github.com/thumbor/thumbor).
CVSS VectorVendor: https://github.com/thumbor/thumbor
Lifecycle Timeline
3Blast Radius
ecosystem impact- 24 pypi packages depend on thumbor (24 direct, 0 indirect)
Ecosystem-wide dependent count for version 7.8.0.
DescriptionCVE.org
Summary
Thumbor's filters:proportion(<value>) filter does not enforce an upper bound on <value> and runs in the post-transform phase. An attacker can trigger extremely large resizes (CPU/memory exhaustion) and cause denial of service.
Details
- Filter implementation:
thumbor/filters/proportion.py valueis parsed as a float (BaseFilter.DecimalNumber) with no maximum.- The filter computes
new_width = source_width * valueandnew_height = source_height * valueand then callsengine.resize(new_width, new_height). - Execution phase:
proportionruns in the default POST_TRANSFORM phase (after the main transform pipeline). This means it can effectively bypass request-level size clamping that happens earlier in the request lifecycle (e.g.,MAX_WIDTH/MAX_HEIGHTapplied toreq.width/req.height).
Documentation states the percentage argument should be 0.0 to 1.0 (docs/proportion.rst), but the implementation does not enforce this constraint.
PoC
Preconditions
- The
proportionfilter is enabled (it is enabled by default viaBUILTIN_FILTERS). - Either:
/unsafe/URLs are allowed (ALLOW_UNSAFE_URL=True, common default in some deployments), OR/unsafe/is disabled, and the attacker has a valid signed URL (i.e., the attacker is an authorized user/partner, or otherwise can obtain signed URLs issued by a trusted signing service).
Example request 1 (signed URL)
The following request was used to reproduce the issue and causes severe resource exhaustion:
http://<host>:<port>/<url-sign>/100x100/filters:proportion(10000)/example.jpg
Example request 2 (/unsafe/)
If /unsafe/ is enabled:
http://<host>:<port>/unsafe/100x100/filters:proportion(10000)/example.jpg
Impact
- Remote Denial of Service via CPU and/or memory exhaustion (and potentially process crash / OOM kill).
- Exploitability depends on deployment:
- If
/unsafe/is enabled: unauthenticated remote DoS. - If
/unsafe/is disabled: the attacker needs a valid signed URL (i.e., the attacker can legitimately request signed URLs, or has access to signed URLs issued for other users/partners). If signed URLs are not exposed to untrusted parties, exploitability is reduced but the risk still applies to any party who can generate/use signed URLs.
Suggested remediation
- Enforce a strict bound on the
proportionparameter (e.g.,0.0 < value <= 1.0as documented), or define a safe maximum based on intended semantics.
AnalysisAI
Remote denial of service in Thumbor (pip/thumbor <= 7.7.7) is triggered by passing an unbounded value to the built-in filters:proportion() image filter, causing the server to allocate extreme CPU and memory resources during resize operations. The filter executes in the POST_TRANSFORM phase - after request-level MAX_WIDTH/MAX_HEIGHT clamping has already run - making those server-side size guards ineffective as a compensating control. Publicly available exploit code (PoC) exists per the GitHub Security Advisory GHSA-phj3-59pf-cp83; the vulnerability is not currently listed in the CISA KEV catalog.
Technical ContextAI
Thumbor is an open-source Python image-processing server (pkg:pip/thumbor) commonly used to serve dynamically resized and filtered images via URL-encoded parameters. The proportion filter in thumbor/filters/proportion.py parses its argument as a BaseFilter.DecimalNumber float with no defined maximum, then computes new_width = source_width * value and new_height = source_height * value before calling engine.resize(). The root cause is CWE-400 (Uncontrolled Resource Consumption): the implementation omits the input validation that its own documentation specifies (0.0 to 1.0 per docs/proportion.rst). The filter's placement in the POST_TRANSFORM pipeline phase is architecturally significant - this phase executes after the main transform pipeline where MAX_WIDTH and MAX_HEIGHT are applied to req.width/req.height, meaning those configuration-level guards do not constrain the proportion filter's output dimensions.
RemediationAI
Upgrade to Thumbor 7.8.0 (vendor-released patch), which enforces that proportion values outside the range (0.0, 1.0] are silently rejected - the filter returns without invoking engine.resize(). The fix is in commit 2c716119de986cfc68c7071af52a98187e006023 and the release is at https://github.com/thumbor/thumbor/releases/tag/7.8.0. If immediate upgrade is not feasible, remove the proportion filter from the BUILTIN_FILTERS configuration list to disable it entirely - trade-off: this removes all proportion-based resize functionality for legitimate users. As a secondary hardening step, if ALLOW_UNSAFE_URL=True, set it to False to force signed URL requirements; this restricts exploitation to authorized parties with signing access but does not eliminate the vulnerability. Rate limiting at the reverse proxy or load balancer on Thumbor processing endpoints can reduce DoS impact but does not remediate the root cause. Note that MAX_WIDTH and MAX_HEIGHT settings alone are not a compensating control because the proportion filter bypasses them via POST_TRANSFORM execution order.
Same weakness CWE-400 – Uncontrolled Resource Consumption
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-51611
GHSA-phj3-59pf-cp83