{
  "parent_root_cause": {
    "cve": "CVE-2026-49857",
    "component": "src/security.ts:isPrivateV6()",
    "mechanism": "IPv4-mapped IPv6 hex normalization bypass. The WHATWG URL parser normalizes http://[::ffff:127.0.0.1] to hostname ::ffff:7f00:1. isPrivateV6() extracted the suffix '7f00:1' and called net.isIPv4('7f00:1') which returns false (hex, not dotted-decimal), so the loopback address was classified non-private and assertSafeUrl() returned the URL as safe.",
    "sink": "ctx.request.get(safeUrl.toString()) at src/tools.ts:234 and page.goto(safeUrl.toString()) at src/browser.ts:66",
    "fix": "177ec5f8ee9c2d5749035777e562f699971b0da9 — reconstruct dotted-decimal IPv4 from the two trailing hex groups of a ::ffff:-prefixed address and run isPrivateV4()."
  },
  "variant_root_cause": {
    "component": "src/tools.ts:233-234 and src/browser.ts:58-66 (assertSafeUrl call site / fetch layer), NOT src/security.ts classification",
    "mechanism": "Redirect-following without re-validation. assertSafeUrl() is invoked exactly once on the initial URL. Playwright ctx.request.get() and page.goto() follow HTTP 3xx redirects to private/loopback IPs without re-invoking assertSafeUrl() on the Location target. A public URL that 302-redirects to a private URL passes the guard (public host) and then reaches the private target unvalidated.",
    "sink": "Same sinks — ctx.request.get() (src/tools.ts:234) and page.goto() (src/browser.ts:66)."
  },
  "equivalence_assessment": {
    "same_guard": true,
    "same_tools": true,
    "same_sink": true,
    "same_trust_boundary": true,
    "same_code_path": true,
    "same_specific_root_cause_mechanism": false,
    "explanation": "Both the parent and this variant defeat the SAME SSRF protection (assertSafeUrl guard) on the SAME tools (download_media / auth_fetch) at the SAME sink (Playwright fetch) across the SAME trust boundary (MCP tool URL argument -> server-side fetch of an internal/loopback IP). They share the same vulnerability CLASS (SSRF guard bypass). However the specific root-cause MECHANISM differs: the parent is an IP-classification defect (hex normalization) inside isPrivateV6(); this variant is a placement defect (the guard is applied once and not on redirect targets) in the fetch orchestration. The 177ec5f fix corrected only the classification defect and does not touch redirect handling, so the placement defect remains and yields a working SSRF on the fixed code.",
    "why_it_is_a_bypass_not_a_separate_unrelated_bug": "Per the variant rules, a separate bug in a different component is not a bypass. This is NOT a different component — it is the same guard, same tools, same sink, same trust boundary. The fix's stated goal (block SSRF to private/loopback via assertSafeUrl) is defeated. It is therefore a bypass of this fix, reached via a different mechanism the fix did not cover.",
    "same_root_cause_confidence": 0.45,
    "same_surface_confidence": 0.9
  },
  "also_tested_same_class_variants": {
    "description": "Same-root-cause CLASS (IPv4-in-IPv6 hex normalization) variants were tested and RULED OUT as a working SSRF in this environment.",
    "candidates": [
      { "input": "http://[::ffff:0:127.0.0.1]/", "normalized": "::ffff:0:7f00:1", "guard_bypass_on_fixed": true, "routes_to_loopback": false, "reason": "IPv4-TRANSLATED form (3 trailing hex groups); fix groups.length===2 too narrow; OS returns ENETUNREACH (kernel does not map ::ffff:0:x:y to IPv4)." },
      { "input": "http://[::127.0.0.1]/", "normalized": "::7f00:1", "guard_bypass_on_fixed": true, "routes_to_loopback": false, "reason": "IPv4-COMPATIBLE (deprecated, no ::ffff:); not routed to IPv4 loopback (ENETUNREACH)." },
      { "input": "http://[64:ff9b::127.0.0.1]/", "normalized": "64:ff9b::7f00:1", "guard_bypass_on_fixed": true, "routes_to_loopback": false, "reason": "NAT64 well-known prefix; only routes to IPv4 with a NAT64 gateway (absent here); ENETUNREACH." }
    ],
    "verdict": "These are guard-incompleteness / defense-in-depth gaps (the fix's groups.length===2 heuristic and prefix checks are too narrow), NOT a confirmed working SSRF in this environment. They are reported so the coding fix can close them too (reject all IPv4-in-IPv6 embeddings via a real IP library). The confirmed exploitable bypass is the redirect-following path above."
  },
  "runtime_proof_refs": {
    "fixed_result": "bundle/logs/vuln_variant/fixed-variant_variant_result.json",
    "main_result": "bundle/logs/vuln_variant/main-variant_variant_result.json",
    "tier1_mechanism": "bundle/logs/vuln_variant/redirect_tier1.json",
    "guard_matrix": "bundle/logs/vuln_variant/probe_guard.log",
    "routing_matrix": "bundle/logs/vuln_variant/routing_test.log"
  }
}
