The vulnerability allows SSRF bypass via the IPv6 address ::, which is the IPv6 representation of the IPv4 all-zeros address. The kernel routes :: to loopback identically to 127.0.0.1, but this semantic equivalence lives in network stack internals, not in the typical developer's threat model when writing HTTP request validation.
The is_private_ip() check almost certainly contains a blocklist of IPv4 ranges: 10.x, 172.16-31.x, 192.168.x, maybe 127.x. What it almost certainly does NOT contain is a model of IPv6-IPv4 equivalence at the kernel routing layer. This isn't a mental model failure — it's an abstraction failure. The function made an implicit claim about its coverage that the implementation couldn't back. It said 'block internal addresses' but delivered 'block these specific IPv4 ranges.' That's a leaky contract, and security-critical code gets away with underspecified contracts like this far too often.
The deeper problem: this is the fourth or fifth mutation of the same SSRF bypass organism. The sequence — block 127.0.0.1 → attacker uses localhost → block localhost → attacker uses 0.0.0.0 → block 0.0.0.0 → now attacker uses :: — isn't a chain of unlucky discoveries. It's guaranteed given how blocklist-based SSRF guards are constructed. Every time someone writes is_private_ip(), they're validating representation rather than semantics. The attacker wins by finding an equivalent representation the literal didn't anticipate.
The fix 'add :: to the blocklist' is locally correct but globally insufficient. It patches this CVE while preserving the architecture that produced the vulnerability. The next IPv6-IPv4 equivalence — ::1, perhaps, or a link-local address under certain kernel configurations — will be the next bypass. The patch creates the illusion of remediation while the underlying failure mode persists.
The three-module propagation (http.get, http.request, http.batch) confirms the flawed check was centralized and reused — meaning a single abstraction gap propagated across the entire request handling surface. Your remediation should not be 'add :: to blocklist.' It should be recognizing that IP-based SSRF guards require comprehensive address family modeling, not incremental blocklisting. Treat any is_private_ip() function as inherently suspicious given this pattern, and audit for other IPv6-IPv4 equivalences your current blocklist doesn't cover.