This article describes the Django vulnerability CVE-2020-7471, which was fixed on February 3, 2020.
Please refer to the following for release information on the official website.
The following versions are affected.
- Django master branch
- Django 3.0
- Django 2.2
- Django 1.11
Vulnerability description[Potential SQL injection via StringAgg(delimiter)]
django.contrib.postgres.aggregates.StringAgg for using the PostgreSQL
STRING_AGG function had a SQL injection vulnerability. It is possible to embed an arbitrary query in the value passed to the
delimiter parameter at initialization.
Proof of Concept
The libraries, Python and database versions used in the sample code are as follows.
- Django 3.0.2
- psycopg2-binary 2.8.4
- Python 3.8.1
- PostgreSQL 9.6.16
Create a database on PostgreSQL in advance, and change the DATABASES of the Django project to connect to PostgreSQL. (The following is a modification example)
Add an application called
example to the Django project and write the following code.
./manage.py makemigrations && ./manage.py migrate to create the database tables to be used this time.
Make test data on the
Next, let’s use
StringAgg on the
shell command. First, check for correct behavior.
foo;bar;test is created between the
; specified in
However, if you set
delimiter="'", it will be like this.
Let’s take a look at the overall query that is actually generated.
Since the character passed to
delimiter is not escaped, SQL with syntax error is generated. If you devise it, you can insert another query into
Which Code Was Wrong and How It Was Fixed
See the GitHub code below for the actual changes.
django.contrib.postgres.aggregates.StringAgg .__init__, the code was to insert
delimiter directly into the expression using Python string embedding.
Therefore, the code was wrapped with
django.db.models.Value once and the value embedding was left to the database.
Since escape processing is not performed in Django, there is no omission of this change and another pattern of SQL injection.