Django's Trunc() and Extract() database functions — the building blocks behind countless "group sales by month" and "extract the weekday" reporting features — shipped with a SQL injection flaw tracked as CVE-2022-34265. If an application passed untrusted input into the kind argument of Trunc() or the lookup_name argument of Extract(), an attacker could smuggle arbitrary SQL into the generated query. That's a direct path to data exfiltration, authentication bypass, or database tampering, depending on what the surrounding query touched and what privileges the database connection held.
The bug is a useful case study precisely because it doesn't look like a "classic" injection point. Django is famous for its ORM shielding developers from raw SQL, and most Trunc()/Extract() usage in the wild is driven by hardcoded values like "day", "month", or "year" — never end-user input. But once a codebase evolves to let users pick their own aggregation granularity (a date-range report with a ?group_by= query parameter, for example), the safety assumption quietly breaks, and the ORM's usual parameterization guarantees don't cover this particular argument.
Affected versions and components
CVE-2022-34265 affects the Django web framework itself, specifically the django.db.models.functions.Trunc and django.db.models.functions.Extract database functions (and their subclasses, such as TruncYear, TruncMonth, TruncDay, ExtractYear, ExtractWeekDay, and similar helpers built on the same base classes).
Per the Django project's own security advisory, the vulnerable versions were:
- Django 2.2 before 2.2.28
- Django 3.2 before 3.2.14
- Django 4.0 before 4.0.6
The fixes landed in Django 2.2.28, 3.2.14, and 4.0.6. The root cause was that the kind and lookup_name values were interpolated into the SQL sent to the database rather than being fully validated against a fixed, safe set of options before use. Applications that only ever pass literal, hardcoded strings to these functions were not exploitable in practice — the risk surfaces specifically where a kind or lookup_name value is derived, even indirectly, from request data, form input, query parameters, or any other source an attacker can influence.
It's worth noting the database backend matters for exploitability nuance: different backends build the underlying SQL for date truncation and extraction differently, so the practical shape of an injectable payload (and the ease of exploitation) can vary across PostgreSQL, MySQL, SQLite, and Oracle. Django's fix addressed the validation at the ORM layer, which closed the hole consistently across backends rather than requiring backend-specific mitigations.
CVSS, EPSS, and KEV context
NVD's entry for CVE-2022-34265 scores it as CVSS v3.1 9.8 (Critical), reflecting a network-exploitable vector with no privileges or user interaction required and a full loss of confidentiality, integrity, and availability if triggered. That score is the standard ceiling NVD applies to unauthenticated SQL injection primitives in general, and it's worth reading alongside the caveat above: real-world exploitability depends entirely on whether a given application actually routes untrusted input into the kind/lookup_name parameters. Plenty of Django deployments never touch that surface at all, which is why treating the CVSS score as a blanket "your app is critical" signal — without checking your own code paths — would be a mistake.
As of this writing, CVE-2022-34265 does not appear on CISA's Known Exploited Vulnerabilities (KEV) catalog, and there's no public evidence of widespread in-the-wild exploitation. That's consistent with the nature of the flaw: it requires a specific, somewhat uncommon coding pattern (user-controlled aggregation kind passed into an ORM date function) rather than being present in every Django app by default. Organizations should still treat "not on KEV" as "not yet mass-exploited," not as "safe to ignore" — internal or custom-built Django applications that expose date-grouping or reporting features to end users are exactly the kind of software that rarely gets the same public scrutiny as a mainstream framework endpoint, and injection vulnerabilities in bespoke code have a long history of being found and abused well after public disclosure.
Timeline
- Disclosure and patch (2022-07-04): Django's security team published an advisory alongside patched releases — 2.2.28, 3.2.14, and 4.0.6 — that corrected the handling of
kindandlookup_nameinTrunc()andExtract(). As is standard practice for the Django project, the fix, advisory, and CVE assignment were coordinated so patches were available at the moment of public disclosure, minimizing the window where the technical details were known but no fix existed. - CVE record published: CVE-2022-34265 was registered to track the issue in public vulnerability databases, allowing downstream dependency scanners and SBOM tooling to flag affected Django versions.
- Ongoing exposure: Because Django is a long-lived, widely forked and vendored framework, older projects pinned to pre-patch 2.2.x, 3.2.x, or 4.0.x releases can remain exposed indefinitely if they never update their
djangodependency — this is the long tail that matters most for supply chain risk, long after the initial disclosure news cycle fades.
Remediation steps
- Upgrade Django. Update to at least 2.2.28, 3.2.14, or 4.0.6 (or a later release in your major-version line). This is the authoritative fix — Django's own validation now rejects unsafe
kind/lookup_namevalues before they reach the database. - Audit for the vulnerable pattern regardless of patch status. Search your codebase for
Trunc(,Extract(, and their named subclasses (TruncDate,TruncHour,ExtractMonth, etc.) and check whether thekindorlookup_nameargument — or any value that feeds into it — originates from request data, serializer input, query strings, or configuration that a user can influence. - Apply allow-list validation defensively. Even after upgrading, treat any user-influenced aggregation parameter as untrusted input: validate it against a fixed set of expected values (
{"year", "month", "day", "week"}, for example) before it ever reaches the ORM. Defense in depth matters here because the underlying pattern — letting user choice drive dynamic SQL construction — is one that framework patches can constrain but application logic ultimately owns. - Re-run your dependency and SBOM inventory. Confirm every service, internal tool, and vendored fork that depends on Django has actually picked up the patched version — not just your primary application repo. Django often ends up embedded in internal admin tools, data pipelines, and reporting dashboards that don't go through the same update cadence as customer-facing services.
- Check database logs for anomalous truncation/extraction syntax. If you suspect prior exposure, review database query logs (where retained) for
EXTRACT/DATE_TRUNC-style calls containing unexpected tokens, comments, or statement terminators around the unit/kind argument.
How Safeguard Helps
Vulnerabilities like CVE-2022-34265 are exactly the kind of risk that gets lost between disclosure and remediation: the framework fix is public, but knowing whether your fleet of services actually calls Trunc() or Extract() with attacker-influenced input — and whether every one of those services has actually upgraded — is a different problem entirely.
Safeguard's software supply chain security platform continuously inventories every dependency across your codebases and build artifacts, so a Django version pinned below 2.2.28, 3.2.14, or 4.0.6 is flagged automatically the moment it's introduced, without waiting for a manual audit cycle. Because Safeguard maps dependencies to the services and repositories that actually consume them, security teams get a precise, prioritized list of which applications need the update rather than a generic "Django is vulnerable somewhere in your org" alert.
Beyond version tracking, Safeguard's SAST and code-analysis capabilities help identify the application-level pattern that makes CVE-2022-34265 exploitable in the first place — user-controlled values flowing into ORM function arguments — so teams can close the gap with allow-list validation even in services that can't be upgraded immediately. Paired with continuous monitoring for newly disclosed CVEs and EPSS/KEV status changes, Safeguard turns "was our Django app ever exposed to this?" from a multi-day forensic exercise into an answer you already have on hand.