Skip to main content

Cómo comprender y mitigar la vulnerabilidad XSS de Jinja2 (CVE-2024-22195)

Escrito por
feature open source

18 de enero de 2024

0 minutos de lectura

El 11 de enero de 2024 se divulgó una vulnerabilidad de seguridad importante en Jinja2, una biblioteca de plantillas de Python ampliamente utilizada. Identificada como CVE-2024-22195, esta vulnerabilidad de scripting entre sitios (XSS) ha generado preocupación por su impacto en numerosos proyectos. Jinja2 registra más de 33 millones de descargas semanales, casi 10,000 estrellas en GitHub y más de 90,000 proyectos dependientes.

La vulnerabilidad afecta a todas las versiones anteriores a la 3.1.3, y la versión 3.1.3, que incluye el parche, es la única opción segura. Cabe destacar que la versión más descargada, la 3.1.2, sigue siendo vulnerable y se usa ampliamente.

Panel de popularidad que muestra las descargas semanales por versión, con la versión 3.1.2 en su punto máximo, con 17.42 millones de descargas.

Puedes comprobar la versión de Jinja2 en tu proyecto consultando el archivo requirements.txt o ejecutando pip list | grep Jinja2 en el entorno virtual de tu proyecto.

Comprender el uso de Jinja2 en el desarrollo con Python

La popularidad de Jinja2 se debe a su capacidad para crear plantillas HTML dinámicas con una sintaxis similar a la de Python. Ofrece funciones como la herencia de plantillas, el escape automático de HTML para evitar ataques XSS mediante entradas que no son de confianza y la compatibilidad con la internacionalización.

Los desarrolladores suelen instalarlo desde PyPI con el comando pip install Jinja2. Un ejemplo de uso en un proyecto podría ser el siguiente:

{% extends "base.html" %}
{% block title %}Members{% endblock %}
{% block content %}
  <ul>
  {% for user in users %}
    <li><a href="{{ user.url }}">{{ user.username }}</a></li>
  {% endfor %}
  </ul>
{% endblock %}

Detalles de la vulnerabilidad XSS

CVE-2024-22195 se origina en el filtro xmlattr de Jinja2 cuando se usan claves con espacios que provienen de entradas del usuario. Esta falla permite a los atacantes inyectar atributos HTML arbitrarios en las plantillas, eludir el mecanismo de escape automático y potencialmente ejecutar scripts no confiables en el navegador del usuario.

A continuación se muestra una reproducción completa de prueba de concepto de la vulnerabilidad de scripting entre sitios en Jinja2, compartida por Calum Hutton, del equipo de investigación de seguridad de Snyk, quien divulgó esta vulnerabilidad:

import sys

from jinja2 import Template

tmpl = Template(u'''\
<!DOCTYPE html>
<html>
  <head>
    <title>{{ title|escape }}</title>
  </head>
  <body>
    <img{{ dict_var|xmlattr }}>
  </body>
</html>
''')

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print(f'% python {sys.argv[0]} <attribute key>')
        sys.exit(1)
    key = sys.argv[1]
    # Could be used to bypass blacklist validation, i.e with the below input we can overwrite
    # the src attribute and add an onerror handler:
    # % python j2_xmlattr.py "src=1 onerror=alert(1) class"
    if key.startswith('on') or key in ('src',):
        print(f'Invalid key: {key}')
        sys.exit(2)
    data = {
        key: 'xxx',
        'src': 'https://jinja.palletsprojects.com/en/3.0.x/_static/jinja-logo-sidebar.png',
        'alt': 'My image'
    }
    print(tmpl.render(
        title='Jinja2 xmlattr PoC',
        dict_var=data
    ))

Reproducción de la vulnerabilidad XSS CVE-2024-22195 de Jinja2 

Crea un nuevo entorno virtual de Python 3:

  1. python3 -m venv myenv 

  2. source myenv/bin/activate

Nota: si estás comenzando a administrar distintos entornos de desarrollo de Python, te recomiendo dedicar unos minutos a leer Cómo dominar los entornos virtuales de Python: guía completa sobre venv, Docker y cómo proteger tu código.

Luego, crea el archivo de dependencias de Python requirements.txt, que usa el administrador de paquetes pip, y agrega bibliotecas comunes del registro de PyPI:

Jinja2==3.1.2
Flask
Werkzeug
Requests
SQLAlchemy
Flask-WTF
Pillow
Flask-SQLAlchemy
Flask-Migrate

Ahora podemos usar Snyk para analizar el proyecto y comprobar si alguna de las dependencias de Python es vulnerable. Si usas macOS, primero instala Snyk con brew, la forma más rápida de comenzar:

brew tap snyk/tap
brew install snyk

Nota: para otros sistemas operativos, como Windows o Linux, consulta las instrucciones de instalación en Snyk User Docs.

Debes autenticarte en Snyk. Ejecuta snyk auth y sigue las instrucciones para iniciar sesión en el navegador; Snyk CLI obtendrá automáticamente las credenciales de API.

Ya podemos analizar nuestro proyecto de Python. Ejecuta lo siguiente:

snyk test

Se mostrarán los hallazgos de Snyk:

Testing /private/tmp/py1...

Tested 23 dependencies for known issues, found 1 issue, 6 vulnerable paths.

Issues to fix by upgrading dependencies:

  Upgrade jinja2@3.1.2 to jinja2@3.1.3 to fix
  ✗ Cross-site Scripting (XSS) (new) [Medium Severity][https://security.snyk.io/vuln/SNYK-PYTHON-JINJA2-6150717] in jinja2@3.1.2
    introduced by jinja2@3.1.2 and 5 other path(s)

Organization:      liran.tal
Package manager:   pip
Target file:       requirements.txt
Project name:      py1
Open source:       no
Project path:      /private/tmp/py1
Licenses:          enabled

Tip: Try `snyk fix` to address these issues.`snyk fix` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems.
See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix

Snyk detectó correctamente la versión vulnerable de Jinja2 utilizada en nuestro proyecto (la versión 3.1.2) y recomendó una solución desde la CLI.

También es una buena oportunidad para contarte que puedes usar una extensión de Snyk en tu IDE y analizar tu propio código Python y tus aplicaciones Python en contenedores, además de analizar dependencias de terceros de PyPI.

La complejidad de explotar esta vulnerabilidad varía según la aplicación específica y cómo implementa Jinja2. Sin embargo, dada la naturaleza de las vulnerabilidades XSS, se recomienda darle máxima prioridad.

Cómo mitigar la vulnerabilidad de Jinja2 y monitorear la seguridad de forma continua

Se recomienda a los desarrolladores actualizar de inmediato a Jinja2 versión 3.1.3 para corregir esta vulnerabilidad.

Además, herramientas como Snyk pueden ser fundamentales para monitorear vulnerabilidades de forma continua. Snyk no solo detecta código y bibliotecas vulnerables mediante su extensión para IDE, sino que también es clave para analizar aplicaciones en contenedores Docker que incluyen esta dependencia vulnerable.

Actualiza Jinja2 a la versión 3.1.3 o posterior. Para hacerlo, modifica tu archivo requirements.txt a Jinja2>=3.1.3 y ejecuta pip install -U -r requirements.txt.

Recursos de seguridad para desarrolladores y próximos pasos

El descubrimiento de CVE-2024-22195 en Jinja2 nos recuerda la importancia de mantener las dependencias actualizadas y usar herramientas como Snyk para monitorear la seguridad de forma continua. Si se mantienen informados y toman medidas proactivas, los desarrolladores pueden proteger sus proyectos frente a este tipo de vulnerabilidades.

Aprende sobre XSS en Python con Snyk Learn: XSS en Python

Guía rápida de buenas prácticas de seguridad en Python: Buenas prácticas de seguridad en Python

Cómo dominar los entornos virtuales de Python: Entornos virtuales de Python

Buenas prácticas para crear contenedores de aplicaciones Python con Docker: Crear contenedores de Python con Docker

Además de mantener Jinja2 actualizado, se recomienda seguir las prácticas generales de seguridad, como validar y depurar todas las entradas de los usuarios, implementar políticas de seguridad de contenido y realizar auditorías de seguridad con regularidad.

Leer más