VYPR
Moderate severityNVD Advisory· Published Dec 2, 2025· Updated Dec 2, 2025

Potential SQL injection in FilteredRelation column aliases on PostgreSQL

CVE-2025-13372

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.

PackageAffected versionsPatched versions
DjangoPyPI
>= 5.2a1, < 5.2.95.2.9
DjangoPyPI
>= 5.1a1, < 5.1.155.1.15
DjangoPyPI
>= 4.2a1, < 4.2.274.2.27

Affected products

1

Patches

5
479415ce5249

[5.2.x] Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.

https://github.com/django/djangoJacob WallsNov 17, 2025via ghsa
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.

https://github.com/django/djangoJacob WallsNov 17, 2025via ghsa
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.

https://github.com/django/djangoJacob WallsNov 17, 2025via ghsa
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.

https://github.com/django/djangoJacob WallsNov 17, 2025via ghsa
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)
    
5b90ca1e7591

Fixed CVE-2025-13372 -- Protected FilteredRelation against SQL injection in column aliases on PostgreSQL.

https://github.com/django/djangoJacob WallsNov 17, 2025via ghsa
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

News mentions

0

No linked articles in our index yet.