Python's built-in str.lower() method can produce a security vulnerability when used inside IDNA domain name encoding, because it applies whatever Unicode version ships with the current interpreter instead of the frozen Unicode 3.2.0 rules the IDNA 2003 standard requires, security engineer Seth Larson wrote on his blog.

The mismatch shows up in the case-folding step of Python's IDNA implementation, which calls str.lower() on characters that lack a listed exception. Larson gives the character U+13A0 as an example: modern Unicode 17.0.0 case-folding encodes it as "xn--kz9aa", while the RFC-compliant Unicode 3.2.0 behavior produces "xn--58da", a different encoded domain entirely.

Python's fix hardcodes a table of exception codepoints where modern str.lower() output diverges from Unicode 3.2.0, so the IDNA encoder can override the interpreter's built-in behavior and stay standards-compliant.

The underlying problem is any code path that assumes a language's standard string methods behave identically across versions and use cases. IDNA needs a version-locked behavior; Python's default string handling does not provide one.

Anything that parses or normalizes domain names, including allowlists, SSRF filters and phishing detection, inherits this risk if it leans on default string casing instead of a library that pins the correct Unicode version. It's worth checking whether your own domain validation code makes the same assumption.