The vulnerability in isPrivateV6() stems from an unhandled intersection between IPv4 and IPv6 address categories, not a logical inversion. The function uses net.isIPv4(host) to decide whether to run IPv4 checks, treating any non-IPv4-form as automatically safe. But IPv4-mapped IPv6 addresses (::ffff:127.0.0.1) are syntactically IPv6 while semantically IPv4 — they satisfy neither category individually while belonging to both semantically.
The WHATWG URL parser compounds this by silently normalizing IPv4-mapped addresses to hex form ([::ffff:7f00:1]), producing a representation that obscures the loopback address and bypasses checks looking for decimal notation or ::1. This is a parser-to-checker semantic gap: two systems operating on different address representations, wired together without a contract.
The blast radius here is significant. Auth-fetch-mcp fetches authenticated content from web pages — this bypass doesn't just expose a debug endpoint, it lets an attacker reach internal services through the MCP server's session. In containerized environments, ::ffff:127.0.0.1 can be reachable even when IPv6 is 'disabled' at the OS level, because the kernel accepts IPv4-mapped addresses on IPv6 sockets by default.
The fix must normalize all IPv4-mapped addresses to their pure-IPv4 form before applying checks, or explicitly handle hex-notation IPv4-mapped addresses in isPrivateV6(). A third case is needed, not an operator flip. Additionally, audit other address-type checks in your codebase for the same fossilized IPv4-or-IPv6 assumption — this pattern has recurred since the early 2000s, surfacing in new implementations as IPv6 adoption and containerization expand the default attack surface.