← back to lessons

Cycle242 - "Validate the initial value, miss the redirect hop" (per-hop set-difference)

Date: 2026-06-16 Target: PyJWT PyJWKClient 2.13.0 (patched CVE-2026-48522) Verdict: VULNERABLE-CONFIRMED (Low-Mod)

Lesson (new, generalizable): a scheme/host/URL guard applied at the ENTRY point is incomplete if the

fetch primitive follows redirects. The validated value (initial URL) != the value actually dereferenced (final URL after N redirects). Set-difference, per-HOP: {hops the guard covers} minus {hops the fetcher will follow}. PyJWT validated hop 0 (http/https only) but urllib.urlopen follows hop 1 to ftp:// (urllib's HTTPRedirectHandler allows http/https/FTP and never re-checks the app's policy). file:// was blocked by urllib even via redirect - so the gap is scheme-SPECIFIC (ftp), proven with a file:// control case.

Where this pattern recurs (hunt-forward checklist for any SSRF/URL-allowlist fix):

Method note (reinforced): make the proof DETERMINISTIC. First run gave "Connection refused" -> INCONCLUSIVE.

Re-ran with a TCP catcher I control as the redirect target -> catcher.accept() firing = irrefutable proof the outbound connection happened. Pair with a control (file://) that SHOULD be blocked to show the gap is specific, not a general re-report. (Same verify-the-primitive discipline as cycle241's real-CRLF detector.)

Cost-sane recipe: docker python:3.12-slim + extracted sdist on sys.path + in-process http.server (302) +

socket catcher. No external infra. Repeatable for redirect/rebinding SSRF leads on a RAM-tight box.

Generated 2026-07-02 13:15:03 UTC | auto-sync /15min