Keep external names out of Django ORM query structure
Django’s FilteredRelation fix separates alias structure from bound values. Give report builders controlled identifiers, alongside supported security updates.
A report builder can bind every filter value and still accept external input in the wrong part of a query. Values describe what to match. Alias names help define query structure. Django’s December 2025 PostgreSQL security fix illustrates why those inputs deserve separate treatment. A controlled vocabulary for report choices keeps application intent visible while supported framework updates address defects in the implementation.
The distinction matters when a product offers configurable columns or saved reports. It is tempting to pass a submitted object directly into a convenient ORM method. That object can contain both user choices and names that the query compiler will interpret structurally. Parameterizing the values does not automatically establish that externally supplied names are appropriate identifiers for the application to accept.
Preserve the advisory’s conditions
The 2 December 2025 Django advisory assigns high severity under Django’s policy to CVE-2025-13372. It concerns FilteredRelation column aliases on PostgreSQL, through a suitably crafted dictionary expanded as **kwargs into QuerySet.annotate() or QuerySet.alias(). The issued releases were 5.2.9, 5.1.15 and 4.2.27. These conditions belong together; “every Django filter is injectable” would misstate the notice.
The 5.2.9 release notes, also dated 2 December, identify the same issue. Looking back from November 2026, these numbers identify the historical fixes, not a recommendation to deploy those exact old patch levels now. A maintained application needs a currently supported release and the relevant later fixes. This article gives a defensive interpretation; it contains no exploit payload or live database test.
Severity is attributed to Django’s policy rather than presented as an independently calculated score. Nor does the advisory establish that a particular application exposed the vulnerable path. Exposure depends on its database, framework version and construction of the affected calls. Those facts require application-specific inspection. Broad reassurance and broad alarm both discard the conditions that make the notice actionable.
Give values and names different paths
A customer’s selected date or order status is a value. A key naming an annotation is part of the program’s query construction. The application can accept a business choice without accepting the submitted string as that annotation name. Resolve a recognised choice to a definition owned by the application, then pass separately validated values through the intended ORM value interface.
For a report builder, that suggests a registry of supported report concepts with stable internal definitions. A visible label can change language without changing the query identifier. A saved report can refer to an approved concept without storing arbitrary query structure. This is an architecture recommendation, not a guarantee that a registry alone establishes security or that every existing report builder needs replacement.
The distinction also helps permissions. A recognised column may still be inappropriate for the current account. Resolving a name successfully should not automatically authorize access to its underlying data. Keep the allowed report vocabulary and the viewer’s access rules explicit. Otherwise a technically well-formed report can reveal information the user was never meant to see, even when query compilation behaves correctly.
Review transformations, not just the request boundary
A useful defensive review follows an input from the request or saved configuration to the affected ORM call. Ask which component chooses dictionary keys, which chooses values and which can replace either. A check at the form boundary may be bypassed by another import path or an older stored report. The relevant question is what can reach the query-construction boundary in the running application.
Stored data deserves attention because storage does not establish trust. A report configuration may have originated in a user-controlled request or an administrative import. If later code expands it directly as keyword arguments, that later code inherits its naming decisions. Record the expected shape and reject unknown concepts at resolution time rather than relying on a past screen having displayed a restricted menu.
Keep this review bounded. It need not become a speculative hunt through unrelated ORM features. Start with the advisory’s methods and conditions, then identify shared helpers used by report construction. The output should explain whether external names can reach those calls and who owns the permitted mapping. An inventory of method names without the surrounding data flow would not answer that question.
Patching and application design do different work
Installing a supported patched framework addresses the framework defect. Limiting the application’s report vocabulary defines what the product intends to permit. Neither action makes the other redundant. A controlled mapping is not a reason to postpone security updates, and a patch is not a reason to accept arbitrary business fields from every user.
When planning a change, preserve intended report behaviour. Unknown identifiers need a clear failure rather than silently falling back to a different column. Existing saved reports may need a mapping to the supported vocabulary. Keep failures visible to the people maintaining those reports so a security improvement does not quietly change what an exported total means.
The strongest counterargument is that many applications use constant aliases written entirely by developers. Such an application may not expose this external naming route at all. That narrows the immediate review; it does not prove the entire application safe or remove the need for supported patches. Evidence about one path should remain evidence about that path.
Make the handover answer a concrete question
For software maintenance, a useful handover identifies the deployed framework line, the affected call sites and the source of their alias names. It should also name the owner of report vocabulary changes. This gives the next maintainer enough context to distinguish an approved product extension from a new external query-structure input.
The durable rule is simple to apply without an ORM slogan: users choose among business concepts the application deliberately supports, while application code owns how those concepts become query structure. Values retain their separate binding path. That arrangement leaves room for flexible reporting and gives reviewers a specific boundary to inspect, alongside the framework’s own security maintenance.
Paul