Potential SQL injection in FilteredRelation column aliases on PostgreSQL
Description
An issue was discovered in 5.2 before 5.2.9, 5.1 before 5.1.15, and 4.2 before 4.2.27. FilteredRelation is subject to SQL injection in column aliases, using a suitably crafted dictionary, with dictionary expansion, as the **kwargs passed to QuerySet.annotate() or QuerySet.alias() on PostgreSQL. Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected. Django would like to thank Stackered for reporting this issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
DjangoPyPI | >= 5.2a1, < 5.2.9 | 5.2.9 |
DjangoPyPI | >= 5.1a1, < 5.1.15 | 5.1.15 |
DjangoPyPI | >= 4.2a1, < 4.2.27 | 4.2.27 |
Affected products
1- Range: 5.2
Patches
5479415ce5249[5.2.x] Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.
5 files changed · +45 −1
django/db/backends/postgresql/compiler.py+10 −1 modified@@ -1,6 +1,6 @@ from django.db.models.sql.compiler import ( SQLAggregateCompiler, - SQLCompiler, + SQLCompiler as BaseSQLCompiler, SQLDeleteCompiler, ) from django.db.models.sql.compiler import SQLInsertCompiler as BaseSQLInsertCompiler @@ -25,6 +25,15 @@ def __str__(self): return "UNNEST(%s)" % ", ".join(self) +class SQLCompiler(BaseSQLCompiler): + def quote_name_unless_alias(self, name): + if "$" in name: + raise ValueError( + "Dollar signs are not permitted in column aliases on PostgreSQL." + ) + return super().quote_name_unless_alias(name) + + class SQLInsertCompiler(BaseSQLInsertCompiler): def assemble_as_sql(self, fields, value_rows): # Specialize bulk-insertion of literal values through UNNEST to
docs/releases/4.2.27.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 4.2.27 release notes Django 4.2.27 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 4.2.26. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.1.15.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.1.15 release notes Django 5.1.15 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 5.1.14. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.2.9.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.2.9 release notes Django 5.2.9 fixes one security issue with severity "high", one security issue with severity "moderate", and several bugs in 5.2.8. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
tests/annotations/tests.py+11 −0 modified@@ -1507,3 +1507,14 @@ def test_alias_filtered_relation_sql_injection(self): ) with self.assertRaisesMessage(ValueError, msg): Book.objects.alias(**{crafted_alias: FilteredRelation("authors")}) + + def test_alias_filtered_relation_sql_injection_dollar_sign(self): + qs = Book.objects.alias( + **{"crafted_alia$": FilteredRelation("authors")} + ).values("name", "crafted_alia$") + if connection.vendor == "postgresql": + msg = "Dollar signs are not permitted in column aliases on PostgreSQL." + with self.assertRaisesMessage(ValueError, msg): + list(qs) + else: + self.assertEqual(qs.first()["name"], self.b1.name)
9c6a5bde2424[5.1.x] Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.
5 files changed · +53 −0
django/db/backends/postgresql/compiler.py+24 −0 added@@ -0,0 +1,24 @@ +from django.db.models.sql.compiler import ( # isort:skip + SQLAggregateCompiler, + SQLCompiler as BaseSQLCompiler, + SQLDeleteCompiler, + SQLInsertCompiler, + SQLUpdateCompiler, +) + +__all__ = [ + "SQLAggregateCompiler", + "SQLCompiler", + "SQLDeleteCompiler", + "SQLInsertCompiler", + "SQLUpdateCompiler", +] + + +class SQLCompiler(BaseSQLCompiler): + def quote_name_unless_alias(self, name): + if "$" in name: + raise ValueError( + "Dollar signs are not permitted in column aliases on PostgreSQL." + ) + return super().quote_name_unless_alias(name)
django/db/backends/postgresql/operations.py+1 −0 modified@@ -24,6 +24,7 @@ def get_json_dumps(encoder): class DatabaseOperations(BaseDatabaseOperations): + compiler_module = "django.db.backends.postgresql.compiler" cast_char_field_without_max_length = "varchar" explain_prefix = "EXPLAIN" explain_options = frozenset(
docs/releases/4.2.27.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 4.2.27 release notes Django 4.2.27 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 4.2.26. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.1.15.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.1.15 release notes Django 5.1.15 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 5.1.14. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
tests/annotations/tests.py+12 −0 modified@@ -2,6 +2,7 @@ from decimal import Decimal from django.core.exceptions import FieldDoesNotExist, FieldError +from django.db import connection from django.db.models import ( BooleanField, Case, @@ -1454,3 +1455,14 @@ def test_alias_filtered_relation_sql_injection(self): ) with self.assertRaisesMessage(ValueError, msg): Book.objects.alias(**{crafted_alias: FilteredRelation("authors")}) + + def test_alias_filtered_relation_sql_injection_dollar_sign(self): + qs = Book.objects.alias( + **{"crafted_alia$": FilteredRelation("authors")} + ).values("name", "crafted_alia$") + if connection.vendor == "postgresql": + msg = "Dollar signs are not permitted in column aliases on PostgreSQL." + with self.assertRaisesMessage(ValueError, msg): + list(qs) + else: + self.assertEqual(qs.first()["name"], self.b1.name)
56aea00c3c5e[6.0.x] Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.
5 files changed · +45 −1
django/db/backends/postgresql/compiler.py+10 −1 modified@@ -1,6 +1,6 @@ from django.db.models.sql.compiler import ( # isort:skip SQLAggregateCompiler, - SQLCompiler, + SQLCompiler as BaseSQLCompiler, SQLDeleteCompiler, SQLInsertCompiler as BaseSQLInsertCompiler, SQLUpdateCompiler, @@ -25,6 +25,15 @@ def __str__(self): return "UNNEST(%s)" % ", ".join(self) +class SQLCompiler(BaseSQLCompiler): + def quote_name_unless_alias(self, name): + if "$" in name: + raise ValueError( + "Dollar signs are not permitted in column aliases on PostgreSQL." + ) + return super().quote_name_unless_alias(name) + + class SQLInsertCompiler(BaseSQLInsertCompiler): def assemble_as_sql(self, fields, value_rows): # Specialize bulk-insertion of literal values through UNNEST to
docs/releases/4.2.27.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 4.2.27 release notes Django 4.2.27 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 4.2.26. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.1.15.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.1.15 release notes Django 5.1.15 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 5.1.14. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.2.9.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.2.9 release notes Django 5.2.9 fixes one security issue with severity "high", one security issue with severity "moderate", and several bugs in 5.2.8. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
tests/annotations/tests.py+11 −0 modified@@ -1540,3 +1540,14 @@ def test_alias_filtered_relation_sql_injection(self): ) with self.assertRaisesMessage(ValueError, msg): Book.objects.alias(**{crafted_alias: FilteredRelation("authors")}) + + def test_alias_filtered_relation_sql_injection_dollar_sign(self): + qs = Book.objects.alias( + **{"crafted_alia$": FilteredRelation("authors")} + ).values("name", "crafted_alia$") + if connection.vendor == "postgresql": + msg = "Dollar signs are not permitted in column aliases on PostgreSQL." + with self.assertRaisesMessage(ValueError, msg): + list(qs) + else: + self.assertEqual(qs.first()["name"], self.b1.name)
f997037b235f[4.2.x] Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.
4 files changed · +45 −0
django/db/backends/postgresql/compiler.py+24 −0 added@@ -0,0 +1,24 @@ +from django.db.models.sql.compiler import ( # isort:skip + SQLAggregateCompiler, + SQLCompiler as BaseSQLCompiler, + SQLDeleteCompiler, + SQLInsertCompiler, + SQLUpdateCompiler, +) + +__all__ = [ + "SQLAggregateCompiler", + "SQLCompiler", + "SQLDeleteCompiler", + "SQLInsertCompiler", + "SQLUpdateCompiler", +] + + +class SQLCompiler(BaseSQLCompiler): + def quote_name_unless_alias(self, name): + if "$" in name: + raise ValueError( + "Dollar signs are not permitted in column aliases on PostgreSQL." + ) + return super().quote_name_unless_alias(name)
django/db/backends/postgresql/operations.py+1 −0 modified@@ -23,6 +23,7 @@ def get_json_dumps(encoder): class DatabaseOperations(BaseDatabaseOperations): + compiler_module = "django.db.backends.postgresql.compiler" cast_char_field_without_max_length = "varchar" explain_prefix = "EXPLAIN" explain_options = frozenset(
docs/releases/4.2.27.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 4.2.27 release notes Django 4.2.27 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 4.2.26. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
tests/annotations/tests.py+12 −0 modified@@ -2,6 +2,7 @@ from decimal import Decimal from django.core.exceptions import FieldDoesNotExist, FieldError +from django.db import connection from django.db.models import ( BooleanField, Case, @@ -1443,3 +1444,14 @@ def test_alias_filtered_relation_sql_injection(self): ) with self.assertRaisesMessage(ValueError, msg): Book.objects.alias(**{crafted_alias: FilteredRelation("authors")}) + + def test_alias_filtered_relation_sql_injection_dollar_sign(self): + qs = Book.objects.alias( + **{"crafted_alia$": FilteredRelation("authors")} + ).values("name", "crafted_alia$") + if connection.vendor == "postgresql": + msg = "Dollar signs are not permitted in column aliases on PostgreSQL." + with self.assertRaisesMessage(ValueError, msg): + list(qs) + else: + self.assertEqual(qs.first()["name"], self.b1.name)
5b90ca1e7591Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.
5 files changed · +45 −1
django/db/backends/postgresql/compiler.py+10 −1 modified@@ -1,6 +1,6 @@ from django.db.models.sql.compiler import ( # isort:skip SQLAggregateCompiler, - SQLCompiler, + SQLCompiler as BaseSQLCompiler, SQLDeleteCompiler, SQLInsertCompiler as BaseSQLInsertCompiler, SQLUpdateCompiler, @@ -25,6 +25,15 @@ def __str__(self): return "UNNEST(%s)" % ", ".join(self) +class SQLCompiler(BaseSQLCompiler): + def quote_name_unless_alias(self, name): + if "$" in name: + raise ValueError( + "Dollar signs are not permitted in column aliases on PostgreSQL." + ) + return super().quote_name_unless_alias(name) + + class SQLInsertCompiler(BaseSQLInsertCompiler): def assemble_as_sql(self, fields, value_rows): # Specialize bulk-insertion of literal values through UNNEST to
docs/releases/4.2.27.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 4.2.27 release notes Django 4.2.27 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 4.2.26. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.1.15.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.1.15 release notes Django 5.1.15 fixes one security issue with severity "high", one security issue with severity "moderate", and one bug in 5.1.14. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
docs/releases/5.2.9.txt+8 −0 modified@@ -7,6 +7,14 @@ Django 5.2.9 release notes Django 5.2.9 fixes one security issue with severity "high", one security issue with severity "moderate", and several bugs in 5.2.8. +CVE-2025-13372: Potential SQL injection in ``FilteredRelation`` column aliases on PostgreSQL +============================================================================================ + +:class:`.FilteredRelation` was subject to SQL injection in column aliases, +using a suitably crafted dictionary, with dictionary expansion, as the +``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias` on +PostgreSQL. + Bugfixes ========
tests/annotations/tests.py+11 −0 modified@@ -1541,6 +1541,17 @@ def test_alias_filtered_relation_sql_injection(self): with self.assertRaisesMessage(ValueError, msg): Book.objects.alias(**{crafted_alias: FilteredRelation("authors")}) + def test_alias_filtered_relation_sql_injection_dollar_sign(self): + qs = Book.objects.alias( + **{"crafted_alia$": FilteredRelation("authors")} + ).values("name", "crafted_alia$") + if connection.vendor == "postgresql": + msg = "Dollar signs are not permitted in column aliases on PostgreSQL." + with self.assertRaisesMessage(ValueError, msg): + list(qs) + else: + self.assertEqual(qs.first()["name"], self.b1.name) + def test_values_wrong_alias(self): expected_message = ( "Cannot resolve keyword 'alias_typo' into field. Choices are: %s"
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
12- docs.djangoproject.com/en/dev/releases/security/mitrevendor-advisory
- github.com/advisories/GHSA-rqw2-ghq9-44m7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-13372ghsaADVISORY
- www.djangoproject.com/weblog/2025/dec/02/security-releases/mitrevendor-advisory
- docs.djangoproject.com/en/dev/releases/securityghsaWEB
- github.com/django/django/commit/479415ce5249bcdebeb6570c72df2a87f45a7bbfghsaWEB
- github.com/django/django/commit/56aea00c3c5e1aacf4ed05f8ee06c2e78f02cea0ghsaWEB
- github.com/django/django/commit/5b90ca1e7591fa36fccf2d6dad67cf1477e6293eghsaWEB
- github.com/django/django/commit/9c6a5bde24240382807d13bc3748d08444709355ghsaWEB
- github.com/django/django/commit/f997037b235f6b5c9e7c4a501491ec45f3400f3dghsaWEB
- groups.google.com/g/django-announceghsamailing-listWEB
- www.djangoproject.com/weblog/2025/dec/02/security-releasesghsaWEB
News mentions
0No linked articles in our index yet.