TL;DR. golang.org/x/net/idna.Lookup.ToASCII runs UTS-46 NFKC mapping
on hostnames, which folds 100 non-ASCII Unicode digit codepoints (math
superscripts, circled digits, fullwidth digits, math-styled digits, and
others) to ASCII 0-9 . A pre-IDNA net.ParseIP check rejects the
non-ASCII input as not-an-IP, hands it to the library, and gets back a
real IPv4 literal. That literal then walks past SSRF allowlists,
NO_PROXY lists, TLS-SNI routers, and cookie-domain validators that
only checked the pre-IDNA value. The fix is a post-IDNA TrimRight + ParseAddr
recheck. The blog has the bug, a runnable proof of concept against
golang.org/x/net/http/httpproxy , the canonical safe pattern, and two
just-shipped registry rules (CodeQL + Semgrep) that catch it in CI.
I ran into this one while writing a Go HTTP client for a private project. I
had a host allowlist, I had idna.Lookup.ToASCII canonicalising the host
before dial, and I still could not convince myself the allowlist held. It
did not.…