{
  "verdict": "confirmed_distinct_bypass",
  "bypass": true,
  "variant_type": "bypass_of_fix",
  "summary": "A distinct, working SSRF bypass of the CVE-2026-49857 fix is confirmed on the FIXED auth-fetch-mcp v3.0.2 server (commit d4dedaf, fix 177ec5f) and on the latest default branch (origin/main, commit a4b9245). The fix only hardened isPrivateV6() against IPv4-mapped IPv6 hex normalization; it did not add re-validation of HTTP redirect targets. assertSafeUrl() is called only on the initial URL (src/tools.ts:233, src/browser.ts:58). Playwright ctx.request.get() (download_media) and page.goto() (auth_fetch) follow 3xx redirects to private/loopback IPs without re-running the guard. A public URL that 302-redirects to a loopback URL bypasses the guard end-to-end.",
  "parent_cve": "CVE-2026-49857",
  "parent_root_cause": "isPrivateV6() in src/security.ts fails to detect IPv4-mapped IPv6 addresses after WHATWG hex normalization (::ffff:127.0.0.1 -> ::ffff:7f00:1), so assertSafeUrl() classifies loopback as non-private.",
  "variant_root_cause": "assertSafeUrl() is applied only to the initial request URL; the fetch layer (Playwright ctx.request.get / page.goto) follows HTTP 3xx redirects to private/loopback targets without re-invoking assertSafeUrl() on the Location target. The 177ec5f fix does not touch redirect handling.",
  "root_cause_relation": "same_ssrf_guard_same_sink_same_trust_boundary_distinct_mechanism",
  "tested_targets": {
    "vulnerable_v3.0.1": {
      "commit_sha": "98f381d1298b6b7e7ff29d7a7851f18ea5f2364c",
      "redirect_bypass_reproduced": true,
      "control_direct_loopback_blocked": true
    },
    "fixed_v3.0.2": {
      "commit_sha": "d4dedaf55c1d39228dbed58807ea1f9fac1328e1",
      "fix_commit": "177ec5f8ee9c2d5749035777e562f699971b0da9",
      "redirect_bypass_reproduced": true,
      "control_direct_loopback_blocked": true,
      "variant_redirect_ssrf": true
    },
    "latest_main": {
      "commit_sha": "a4b92452dc9332fb4063225f3d8842f3602a54a3",
      "redirect_bypass_reproduced": true,
      "control_direct_loopback_blocked": true
    }
  },
  "evidence": {
    "reproduction_script": "bundle/vuln_variant/reproduction_steps.sh",
    "script_exit_code": 0,
    "idempotent_rerun_exit_code": 0,
    "runtime_manifest": "bundle/vuln_variant/runtime_manifest.json",
    "fixed_result": "bundle/logs/vuln_variant/fixed-variant_variant_result.json",
    "main_result": "bundle/logs/vuln_variant/main-variant_variant_result.json",
    "vuln_result": "bundle/logs/vuln_variant/vuln-variant_variant_result.json",
    "tier1_mechanism": "bundle/logs/vuln_variant/redirect_tier1.json",
    "guard_probe": "bundle/logs/vuln_variant/probe_guard.log",
    "routing_probe": "bundle/logs/vuln_variant/routing_test.log",
    "key_fixed_excerpt": "download_media returned {downloaded:1, total:2}: control http://127.0.0.1:18080/direct-control -> error 'Refusing to fetch 127.0.0.1 (resolves to private/loopback/link-local address 127.0.0.1)'; variant http://httpbin.org/redirect-to?...#v -> localPath file-1.bin size 42 containing the secret marker. Victim log: 'Request from 127.0.0.1 path=/ host=127.0.0.1:18080'."
  },
  "negative_findings": {
    "ipv4_in_ipv6_hex_class_variants": "The same-root-cause CLASS variants http://[::ffff:0:127.0.0.1]/, http://[::127.0.0.1]/, and http://[64:ff9b::127.0.0.1]/ bypass the FIXED guard's string check (isPrivateV6 returns false) BUT the OS does not route them to IPv4 loopback (connect ENETUNREACH in this environment). Therefore they are guard-incompleteness / defense-in-depth gaps, NOT a confirmed working SSRF here. Reported in patch_analysis.md GAP 2 for completeness; the coding fix should still reject all IPv4-in-IPv6 embeddings.",
    "dns_rebinding": "Noted as a separate SSRF class (TOCTOU on dns.lookup) not covered by 177ec5f; not exercised at runtime in this run and not claimed as part of this bypass."
  },
  "blocking_mitigation_present": false,
  "recommendation": "Re-validate every URL the fetch layer actually requests, including 3xx redirect targets, through assertSafeUrl(); or disable auto-redirect at the guard boundary and follow redirects manually with per-hop validation; or pin to the guard's resolved IP and reject redirects to private/loopback/link-local targets. Also broaden isPrivateV6() to reject all IPv4-in-IPv6 embeddings (mapped/translated/compatible/NAT64) and use fe80::/10 for link-local.",
  "confidence": 0.9
}
