Cloudanix VulnDB

CVE-2026-1287

Medium · 5.4

CVSS

5.4

EPSS

0.9%

Published

Feb 3, 2026

CISA due date

—

Cloudanix analysis

Next patch cycle SSVC: Track

Some Django applications may let a logged-in user manipulate database queries if the application turns specially crafted input names into query aliases.

Exploitation
Remote Authenticated
Attacker needs
Low Privilege
Complexity
Low
Impact
Data Tampering
Component
Web Framework
Class
SQL Injection
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

This is a SQL injection weakness in Django's ORM query construction when FilteredRelation is used with column aliases derived from a crafted dictionary expanded as **kwargs into QuerySet methods such as annotate(), aggregate(), extra(), values(), values_list(), or alias(). Control characters in attacker-influenced alias names can alter the generated SQL. Exploitation generally requires an application code path that accepts untrusted input, builds a dictionary from it, and expands that dictionary into one of the affected ORM methods. The likely impact is limited unauthorized data exposure or modification within the privileges of the application's database account; the CVSS vector indicates network reachability, low attack complexity, required low privileges, no user interaction, and low confidentiality/integrity impact without expected availability impact.

Why it matters to the business

Applications built on vulnerable Django versions may allow an authenticated or otherwise authorized user to manipulate database queries if the application passes user-controlled dictionary keys into affected ORM methods. This can expose sensitive records, alter query results, bypass business logic enforced at the query layer, or modify data depending on the surrounding application code and database permissions. The issue is not listed in CISA KEV, is not known to be used in ransomware campaigns, has low EPSS probability, and has no public exploit maturity reported, but it has been public for 187 days and should be remediated during normal patch cycles, with higher priority for applications exposing dynamic filtering, reporting, search, analytics, or admin-like query-building features.

How an attack unfolds

An attacker first identifies an application feature that accepts structured input used to build Django ORM query arguments, such as dynamic filters, annotations, reports, exports, dashboards, or API query parameters. The attacker supplies a dictionary whose keys become ORM aliases and embeds control characters in those keys. If the application expands that dictionary with **kwargs into an affected QuerySet method while using FilteredRelation, vulnerable Django versions may generate malformed or attacker-influenced SQL. The resulting SQL can change the intended query semantics, potentially exposing rows or fields the attacker should not see or affecting integrity of query results. Practical exploitation depends heavily on application-specific code paths and whether untrusted input can reach the affected ORM API as alias names.

How to fix it

Upgrade Django to a fixed supported release: Django 6.0.2 or later for the 6.0 series, Django 5.2.11 or later for the 5.2 LTS series, or Django 4.2.28 or later for the 4.2 LTS series. For source builds, ensure the Django tree includes commit ba00558ddac694d92b05d12ecd2a5b7fcc1de025 or the equivalent vendor backport. Unsupported Django series such as 5.0.x, 4.1.x, and 3.2.x were not fully evaluated and should be upgraded to a supported fixed series rather than relied upon. As defense in depth, do not pass user-controlled dictionary keys directly into ORM **kwargs; allowlist valid alias names, normalize or reject control characters in keys, keep untrusted input as parameter values rather than SQL identifiers, and avoid exposing generic ORM query builders to users.

How to confirm the fix worked

Confirm the installed Django version is 6.0.2 or later, 5.2.11 or later, or 4.2.28 or later using package inventory, dependency lockfiles, container image SBOMs, runtime checks such as django.get_version(), or package manager output such as pip show django. For source-based deployments, verify the fixed commit ba00558ddac694d92b05d12ecd2a5b7fcc1de025 or an equivalent backport is present. Review application code for FilteredRelation combined with annotate(), aggregate(), extra(), values(), values_list(), or alias(), especially where **kwargs are built from request data, JSON object keys, query parameter names, form fields, or API payload keys. Add regression tests that submit alias names containing control characters and confirm they are rejected by application validation or safely handled by the patched framework without altering SQL semantics.

Typical attack path

  1. Find a Django-backed endpoint that accepts user-controlled structured parameters for filtering, reporting, aggregation, annotations, search, exports, or dashboards.
  2. Determine whether the endpoint reflects user-supplied dictionary keys into ORM aliases or annotations rather than treating them only as values.
  3. Submit crafted alias names containing encoded control characters such as newline, carriage return, or tab characters.
  4. Trigger a QuerySet method such as annotate(), aggregate(), extra(), values(), values_list(), or alias() in a code path that also uses FilteredRelation.
  5. Observe changed query behavior, SQL errors, unexpected records, or altered response structure to refine the payload.
  6. Use the manipulated SQL generated by the ORM to access or influence data within the permissions of the application's database account.

How to detect it

To determine whether this was already exploited, focus on code paths that use FilteredRelation with annotate(), aggregate(), extra(), values(), values_list(), or alias() and accept dynamic user input. Review web access logs, API gateway logs, WAF logs, and application request logs for query parameter names or JSON object keys containing URL-encoded or escaped control characters such as newline, carriage return, or tab. Review Django application logs for database exceptions, SQL syntax errors, suspicious stack traces involving FilteredRelation or affected QuerySet methods, and unexpected errors after requests with unusual parameter names. Review database audit logs for abnormal SELECT statements generated by the application account, especially queries with unexpected line breaks, comments, boolean operators, UNION-like constructs, or changed WHERE/JOIN behavior around aliases. Successful exploitation may not leave a unique signature and may appear as normal application database activity, so correlate suspicious requests with application responses, database errors, and unusual access to records or exports.

  • %0a
  • %0A
  • %0d
  • %0D
  • %09
  • \u000a
  • \u000A
  • \u000d
  • \u000D
  • \u0009
  • FilteredRelation
  • django.db.utils.ProgrammingError
  • django.db.utils.OperationalError
  • django.db.utils.DataError
  • annotate()
  • aggregate()
  • values_list()
  • alias()
  • QuerySet

What your security team should do

  • Inventory all applications and images using Django and prioritize upgrades for internet-facing applications and applications with dynamic filtering, analytics, reporting, export, or admin query features.
  • Upgrade affected supported branches to Django 6.0.2+, 5.2.11+, or 4.2.28+; migrate unsupported branches to a supported fixed release.
  • Search code for FilteredRelation and affected QuerySet methods combined with **kwargs expansion from request-controlled data.
  • Add input validation that rejects control characters in user-supplied field names, alias names, JSON keys, and query parameter names used to construct ORM arguments.
  • Review database account privileges used by applications and ensure least privilege to limit the blast radius of query manipulation.
  • Enable or tune application, web, and database logging for anomalous request keys containing encoded control characters and SQL syntax errors from Django-generated queries.
  • Perform retrospective log review for suspicious requests and database errors before and after patching, especially on endpoints that build dynamic ORM queries.

The record

An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. `FilteredRelation` is subject to SQL injection in column aliases via control characters, using a suitably crafted dictionary, with dictionary expansion, as the `**kwargs` passed to `QuerySet` methods `annotate()`, `aggregate()`, `extra()`, `values()`, `values_list()`, and `alias()`. 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 Solomon Kebede for reporting this issue.

Affected packages

Ecosystem Package Introduced Fixed
PyPI django 4.2a1 4.2.28
PyPI django 5.2a1 5.2.11
PyPI django 6.0a1 6.0.2
Bitnami django 4.2.0 4.2.28
Chainguard authentik 0 2025.12.1-r2
Chainguard authentik-fips 0 2025.12.1-r2
Chainguard awx 0 24.6.1-r27
Chainguard label-studio 0 1.22.0-r3
Mageia:9 python-django 0 4.1.13-1.10.mga9
SUSE:Linux Enterprise Module for Package Hub 15 SP7 python-Django 0 4.2.11-150600.3.47.1
openSUSE:Leap 15.6 python-Django 0 4.2.11-150600.3.47.1
openSUSE:Leap 16.0 python-Django 0 5.2.4-bp160.5.1
openSUSE:Tumbleweed python-Django 0 5.2.11-1.1
openSUSE:Tumbleweed python-Django4 0 4.2.28-1.1
openSUSE:Tumbleweed python-Django6 0 6.0.2-1.1

Related vulnerabilities