Skip to main content

Understanding and mitigating the Jinja2 XSS vulnerability (CVE-2024-22195)

Written by:
wordpress-sync/feature-open-source

January 18, 2024

0 mins read

On January 11th, 2024, a significant security vulnerability was disclosed in Jinja2, a widely used Python templating library. Identified as CVE-2024-22195, this cross-site scripting (XSS) vulnerability has raised concerns due to its impact on numerous projects. Jinja2 boasts over 33 million weekly downloads, nearly 10,000 GitHub stars, and over 90,000 dependent projects.

The vulnerability affects all versions prior to 3.1.3, with the patched version 3.1.3 being the only safe option. Notably, the most downloaded version, 3.1.2, remains vulnerable and widely used.

blog-jinga2-vuln

How do I check if my project is using a vulnerable version of Jinja2?

You can check the version of Jinja2 in your project by looking at the requirements.txt file or by running pip list | grep Jinja2 in your project's virtual environment.

Understanding Jinja2 usage in Python development

Jinja2's popularity stems from its ability to create dynamic HTML templates using Python-like syntax. It offers features like template inheritance, HTML auto-escaping to prevent XSS from untrusted input, and internationalization support.

Developers typically install it via PyPI using the command pip install Jinja2. An example usage in a project might look like this:

1{% extends "base.html" %}
2{% block title %}Members{% endblock %}
3{% block content %}
4  <ul>
5  {% for user in users %}
6    <li><a href="{{ user.url }}">{{ user.username }}</a></li>
7  {% endfor %}
8  </ul>
9{% endblock %}

Details of the XSS vulnerability

CVE-2024-22195 arises from the xmlattr filter in Jinja2 when keys containing spaces are used, based on user input. This flaw allows attackers to inject arbitrary HTML attributes into templates, circumventing the auto-escaping mechanism and potentially leading to the execution of untrusted scripts in a user's browser.

Following is a complete proof-of-concept reproduction of the cross-site scripting vulnerability in Jinja2, courtesy of Calum Hutton from the Snyk security research team, who disclosed this vulnerability:

1import sys
2
3from jinja2 import Template
4
5tmpl = Template(u'''\
6<!DOCTYPE html>
7<html>
8  <head>
9    <title>{{ title|escape }}</title>
10  </head>
11  <body>
12    <img{{ dict_var|xmlattr }}>
13  </body>
14</html>
15''')
16
17if __name__ == '__main__':
18    if len(sys.argv) < 2:
19        print(f'% python {sys.argv[0]} <attribute key>')
20        sys.exit(1)
21    key = sys.argv[1]
22    # Could be used to bypass blacklist validation, i.e with the below input we can overwrite
23    # the src attribute and add an onerror handler:
24    # % python j2_xmlattr.py "src=1 onerror=alert(1) class"
25    if key.startswith('on') or key in ('src',):
26        print(f'Invalid key: {key}')
27        sys.exit(2)
28    data = {
29        key: 'xxx',
30        'src': 'https://jinja.palletsprojects.com/en/3.0.x/_static/jinja-logo-sidebar.png',
31        'alt': 'My image'
32    }
33    print(tmpl.render(
34        title='Jinja2 xmlattr PoC',
35        dict_var=data
36    ))

Reproducing the Jinja2 CVE-2024-22195 XSS vulnerability 

Initiate a new Python 3 virtual environment:

  1. python3 -m venv myenv 

  2. source myenv/bin/activate

Note: if you are new to managing different Python development environments, I recommend taking a few minutes to read about mastering Python virtual environments: a complete guide to venv, Docker and securing your code.

Then, create the Python dependency file requirements.txt that the pip package manager uses and add common libraries from the PyPI registry:

1Jinja2==3.1.2
2Flask
3Werkzeug
4Requests
5SQLAlchemy
6Flask-WTF
7Pillow
8Flask-SQLAlchemy
9Flask-Migrate

Now, we can use Snyk to scan the project and see if any of our Python dependencies is vulnerable. If you’re on a macOS, install Snyk first through brew, which is the quickest way to get started:

1brew tap snyk/tap
2brew install snyk

Note: for other operating systems like Windows or Linux, view install instructions on the Snyk User Docs.

You need to authenticate to snyk, so run snyk auth and follow the instructions to log in through the browser, and the Snyk CLI will automatically obtain the API credentials for you.

We’re now ready to scan our Python project. Run the following:

1snyk test

You’ll be presented with Snyk findings:

1Testing /private/tmp/py1...
2
3Tested 23 dependencies for known issues, found 1 issue, 6 vulnerable paths.
4
5Issues to fix by upgrading dependencies:
6
7  Upgrade jinja2@3.1.2 to jinja2@3.1.3 to fix
8  ✗ Cross-site Scripting (XSS) (new) [Medium Severity][https://security.snyk.io/vuln/SNYK-PYTHON-JINJA2-6150717] in jinja2@3.1.2
9    introduced by jinja2@3.1.2 and 5 other path(s)
10
11Organization:      liran.tal
12Package manager:   pip
13Target file:       requirements.txt
14Project name:      py1
15Open source:       no
16Project path:      /private/tmp/py1
17Licenses:          enabled
18
19Tip: 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.
20See 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 successfully detected the vulnerable Jinja2 version used in our project (version 3.1.2), and recommended a fix from the CLI.

This is a great opportunity to let you know you can also use a Snyk extension in your IDE and scan your own Python code and Python containerized applications, on top of scanning 3rd-party dependencies from PyPI.

Is the Jinja2 XSS vulnerability easy to exploit?

The complexity of exploiting this vulnerability varies based on the specific application and its implementation of Jinja2. However, due to the nature of XSS vulnerabilities, it's advisable to treat it with high priority.

Mitigating Jinja2 vulnerability and continuous security monitoring

Developers are urged to upgrade to Jinja2 version 3.1.3 immediately to address this vulnerability.

Additionally, using tools like Snyk can be vital for ongoing vulnerability monitoring. Snyk not only detects vulnerable code and libraries through its IDE extension but is also crucial in scanning containerized applications with Docker that bundle this vulnerable dependency.

How can I protect my project from the Jinja2 XSS vulnerability?

Update Jinja2 to version 3.1.3 or newer. You can do this by modifying your requirements.txt file to Jinja2>=3.1.3 and running pip install -U -r requirements.txt.

Developer security resources and what’s next?

The discovery of CVE-2024-22195 in Jinja2 serves as a reminder of the importance of keeping dependencies up-to-date and utilizing tools like Snyk for continuous security monitoring. By staying informed and proactive, developers can safeguard their projects against such vulnerabilities.

Learn about XSS in Python with Snyk Learn: XSS in Python

Python security best practices cheat sheet: Python Security Best Practices

Mastering Python virtual environments: Python Virtual Environments

Best practices for containerizing Python applications with Docker: Containerizing Python with Docker

Are there any other recommended security practices for Jinja2 users?

Apart from keeping Jinja2 up-to-date, users should follow general security best practices like validating and sanitizing all user inputs, implementing content security policies, and conducting regular security audits.

wordpress-sync/feature-open-source

Level Up Your CI/CD Pipelines

See how these 8 tips can help you catch security issues in the pipe BEFORE you push to production ⭐️