Cuando str.lower() es una vulnerabilidad de seguridad en Python

When str.lower() is a security vulnerability in Python – Seth Larson

Cuando str.lower() es una vulnerabilidad de seguridad en Python

Seth Larson descubre que la función str.lower() de Python puede ser explotada como vulnerabilidad de seguridad en el contexto de IDNA 2003. El problema surge porque str.lower() utiliza la versión de Unicode del intérprete, mientras que StringPrep (RFC 3454) requiere Unicode 3.2.0. Esto provoca inconsistencias en la codificación de nombres de dominio internacionalizados, como se demuestra con el ejemplo de 'ᎠᎠ'. La solución consistió en añadir excepciones para que str.lower() se comporte según Unicode 3.2.0 en casos específicos, corrigiendo la vulnerabilidad CVE-2026-17084.

La llamada a str.lower() en esta función es una vulnerabilidad, porque str utiliza los datos Unicode que vienen con el intérprete de Python, y eso puede diferir de la versión Unicode 3.2.0 requerida por StringPrep.
  1. echoangle

    > Esto es por lo que llamar a str.lower() representa una diferencia entre la implementación y la especificación, y por tanto una vulnerabilidad:

    Me gustaría que hubiera alguna explicación de cómo esto es una vulnerabilidad y no solo un fallo que genera datos erróneos.

    Para mí, vulnerabilidad suena como si hubiera una forma razonable de crear un exploit a partir del fallo, y no veo ninguna aquí, siendo alguien que no está muy familiarizado con el tema.

  2. tialaramex

    Esta idiotez es una gran parte de por qué era tan importante que la gente de Python que trabaja en implementaciones de TLS entendiera que el mecanismo definido para los SAN (no, el "alternativo" en Subject Alternative Name no significa en el sentido de más de uno; X.509 es originalmente para el sistema X.500 e Internet reutilizó X.509, así que estos son nombres alternativos desde Internet) dice que estos son nombres DNS, específicamente no deben entenderse como algún tipo de texto legible por humanos, y por tanto "decodificarlos" a Unicode es definitivamente un sinsentido aunque Python realmente quería hacerlo y creo que solía hacerlo o al menos lo proponía.

    La regla de cómo los SAN DnsNames coinciden con nombres similares, según el DNS, es muy, muy simple para que no la estropees. Manejas un solo comodín (ASCII * código 42 coincide con cualquier etiqueta DNS individual) y más allá de eso es literalmente comparación de bytes. No te importa qué significan esos bytes, o los bytes son todos idénticos o eso no es una coincidencia y hemos terminado.

  3. ummonk

    > La solución fue crear nuevas excepciones para que str.lower() se comportara como si estuviera usando Unicode 3.2.0 solo para una función particular. Así que recorremos cada punto de código Unicode y registramos cuándo el comportamiento de str.lower() es diferente al comparar la versión de Unicode incluida con Python y Unicode 3.2.0.

    Esto suena como una solución bastante chapucera en comparación con implementar un lower congelado separado de Unicode 3.2.0.

  4. jooon

    Me recuerda a un antiguo incidente de seguridad en Spotify https://engineering.atspotify.com/2013/06/creative-usernames

  5. ike_sh

    Me pasó una vez con el signo de Kelvin. Tardé vergonzosamente mucho en encontrarlo.

Más de este día

2026-08-25