On February 3, 2026, the Django Security Team published one of the largest security releases in the framework's history: 6 CVEs patched simultaneously across all maintained versions (4.2, 5.2, and 6.0). Three of those CVEs were SQL injection vulnerabilities rated HIGH severity — meaning an attacker could potentially read, modify, or delete data in your database without authentication.
Then, one month later on March 4, 2026, Django issued another security release covering 2 more CVEs. For Python teams relying on Django as their backbone framework, 2026 has been a demanding year to stay on top of patches. This article walks you through every CVE published so far, the underlying patterns causing them, and the most reliable way to ensure you're never running a vulnerable version.
The February 2026 Django Security Release: 3 SQL Injections in One Shot
The February 3 release — which bumped Django to versions 6.0.2, 5.2.11, and 4.2.28 — addressed a cluster of SQL injection vulnerabilities all rooted in the same code pattern: unsanitized inputs reaching the query layer through Django's ORM internals.
| CVE | Severity | Component | Attack vector |
|---|---|---|---|
CVE-2026-1207 |
HIGH | PostGIS RasterField |
Unsanitized band index used as SQL parameter — enables arbitrary SQL injection via GIS raster queries. Actively exploited since Feb 26, 2026. |
CVE-2026-1287 |
HIGH | FilteredRelation + **kwargs |
Control characters in column alias names bypass sanitization inside FilteredRelation expressions |
CVE-2026-1312 |
HIGH | QuerySet.order_by() + FilteredRelation |
Dot characters (.) in aliases passed to order_by() enable arbitrary SQL injection |
CVE-2026-25673 |
MEDIUM — CVSS 6.3 | URLField Unicode normalization |
Specially crafted Unicode input on Windows triggers a denial of service via infinite normalization loop |
CVE-2026-25674 |
LOW | File/directory permissions | Newly created files and directories may receive incorrect permissions in specific configurations |
All five vulnerabilities affect Django 4.2 before 4.2.28, 5.2 before 5.2.11, and 6.0 before 6.0.2. If you're running any older version, your application is exposed to these attack vectors right now.
requirements.txt, Pipfile.lock, or poetry.lock pins Django below 4.2.28 / 5.2.11 / 6.0.2, upgrade immediately. SQL injection vulnerabilities (CVE-2026-1207, CVE-2026-1287, CVE-2026-1312) can lead to full database compromise without authentication.
The FilteredRelation Pattern: A Recurring Vulnerability Class
What makes this batch of CVEs particularly notable is that it's not a brand new attack surface — it's a recurring pattern. The root of CVE-2026-1287 and CVE-2026-1312 traces back to CVE-2022-28346, a SQL injection via **kwargs filtering that was discovered in April 2022. Despite the original fix, subsequent code paths in FilteredRelation and order_by() contained the same unsanitized input pattern.
The Django Security Team itself acknowledged this in a blog post published the day after the release:
"Almost every report now is a variation on a prior vulnerability. Instead of uncovering new classes of issues, these reports explore how an underlying pattern from a recent advisory might surface in a similar code path." — Django Security Team, February 4, 2026
They also noted something new: attackers and researchers are increasingly using large language models to generate variations of known CVE patterns across similar code paths. This means the velocity of vulnerability discovery is likely to increase — making continuous dependency monitoring more critical than ever.
The Worst Django CVE in Recent History: CVE-2025-64459 (CVSS 9.1)
While February 2026's batch drew attention for its volume, 2025 produced what is considered the most severe Django CVE in years: CVE-2025-64459, rated CVSS 9.1 CRITICAL.
Published November 6, 2025, it affected Django's Q() objects and QuerySet.filter() via the _connector parameter. The attack vector was particularly alarming: no authentication required, low attack complexity, full data exposure. An unauthenticated attacker could craft a request that bypasses authorization, exfiltrates data, or escalates privileges — all through a normal HTTP request.
Q() objects and QuerySet.filter() using the _connector parameter. Patched in Django 5.2.8, 5.1.14, and 4.2.26. Public proof-of-concept available on GitHub. No authentication required to exploit.
Django's Full CVE History: 2025 Was the Worst Year Yet
Putting 2026 in context, the historical data from the official Django security archive and CVEDetails reveals a clear trend: vulnerability discovery is accelerating.
The 16 CVEs counted in 2025 represent a record for the Django framework — nearly double the 9 CVEs recorded in 2024. With 6 CVEs already published in Q1 2026, the trajectory suggests 2026 could be equally demanding.
Why Does Django Keep Seeing SQL Injection Vulnerabilities?
Django is widely praised for its ORM, which is supposed to abstract away raw SQL and prevent injection by default. So why do these vulnerabilities keep appearing?
The answer lies in the interface between user-controlled data and ORM internals. When you use features like FilteredRelation, RawSQL, order_by() with dynamic arguments, or PostGIS geo-queries, you're working with an interface that's more complex than a simple Model.objects.filter(field=value). These advanced APIs often handle column names, alias strings, or index parameters as raw strings before they reach the SQL parameterization layer.
The recurring pattern across CVE-2022-28346, CVE-2025-64459, CVE-2026-1287, and CVE-2026-1312 is always the same: a string that seems like a column name or alias passes through the ORM without full sanitization. A dot, a control character, or an unexpected keyword in that string becomes SQL.
# Pattern at risk — dynamic **kwargs with FilteredRelation
# CVE-2026-1287 : control characters in alias bypass sanitization
queryset = MyModel.objects.annotate(
related=FilteredRelation('foreign_key', condition=Q(**{user_input: value}))
)
# Pattern at risk — dynamic order_by with alias containing dot
# CVE-2026-1312
queryset = MyModel.objects.order_by(f'related.{user_input_field}')
# Safe pattern — whitelist your field names
ALLOWED_ORDER_FIELDS = {'name', 'created_at', 'status'}
order_field = request.GET.get('order', 'created_at')
if order_field not in ALLOWED_ORDER_FIELDS:
order_field = 'created_at'
queryset = MyModel.objects.order_by(order_field)
Django CVE Monitoring: What Your Stack Looks Like in Practice
If you're using Django in a typical production environment, your requirements.txt probably looks something like this:
Django==5.2.10 # ← vulnerable to CVE-2026-1207, -1287, -1312
djangorestframework==3.15.2
psycopg2-binary==2.9.9
django-environ==0.11.2
celery==5.4.0
Pillow==10.3.0
The problem isn't just knowing about CVE-2026-1207 when it's published — it's knowing the exact moment your pinned version becomes vulnerable. A vulnerability can be quietly added to the OSV database days after the official advisory. Without continuous monitoring, your Django 5.2.10 install could be silently exposed for weeks before your next audit.
This is precisely what CVE OptiBot monitors automatically: upload your requirements.txt or poetry.lock, and the scanner checks daily against the OSV.dev database — the same database that powers pip-audit, but with continuous monitoring and email alerts when new vulnerabilities match your exact versions.
9 Security Best Practices for Django Applications in 2026
Beyond keeping Django itself up to date, the following practices significantly reduce your attack surface:
- Update to Django 6.0.2 / 5.2.11 / 4.2.28 immediately. These versions contain patches for all Q1 2026 CVEs. Check your pinned version in
requirements.txtorpoetry.lock. - Never pass raw user input as field names in
**kwargsfilters. This is the root cause of CVE-2022-28346, CVE-2026-1287, and CVE-2026-1312. Whitelist all allowed field names before using them in ORM calls. - Avoid
RawSQL,extra(), andcursor.execute()with user data. Use Django's ORM parameterized queries instead — they handle escaping automatically. - Set
DEBUG = Falsein production. Debug mode exposes full tracebacks that reveal your data model, SQL queries, and environment variables to anyone who triggers an error. - Store
SECRET_KEYin an environment variable, never insettings.py. Usedjango-environor Python'sos.environ. - Enable
SecurityMiddlewareand configure HTTPS. This covers HSTS, XSS headers, and content type sniffing protection in one middleware. - Use
django-axesordjango_ratelimitfor brute-force protection. Django's built-in auth doesn't rate-limit login attempts. - Monitor transitive dependencies, not just Django itself. 25% of teams only track direct dependencies (Snyk 2024) — a vulnerable transitive dependency like
urllib3orcryptographyis just as dangerous. - Automate your CVE monitoring. Running
pip auditin CI catches vulnerabilities at deploy time, but not 3 weeks later when a new CVE lands. Use a continuous monitoring tool that alerts you in real time.
Frequently Asked Questions
Which versions of Django are affected by the February 2026 CVEs?
All Django versions below 4.2.28, 5.2.11, and 6.0.2 are affected by CVE-2026-1207, CVE-2026-1287, and CVE-2026-1312. If you're running Django 3.x or any 4.x version below 4.2.28, those versions are also in the vulnerable range, and you should upgrade to a maintained branch immediately. Django 3.x and 4.0/4.1 are no longer receiving security updates.
Is CVE-2026-1312 exploitable without authentication?
It depends on how your application uses QuerySet.order_by() with FilteredRelation aliases. If user-controlled input is ever passed as an order parameter or alias name, it can be exploited without any authentication. The Django Security Team classifies it as HIGH severity with potential for arbitrary SQL execution.
How do I check if my Django version has known CVEs right now?
Run pip audit in your project's virtual environment to scan against the OSV database. For continuous monitoring (so you're alerted when new CVEs are published that match your current version), you can upload your requirements.txt or poetry.lock to CVE OptiBot — it monitors daily and emails you when new vulnerabilities match your stack.
Does using Django's ORM protect me from SQL injection by default?
For standard queryset operations like Model.objects.filter(field=value), yes — Django uses parameterized queries that prevent injection. The vulnerabilities in Q1 2026 (and historically) occur specifically in advanced ORM features like FilteredRelation, RawSQL, order_by() with dynamic arguments, and PostGIS queries. Avoid passing user-controlled data as field names or aliases in these APIs.
How often should I update Django in production?
For security releases (which use a X.Y.Z versioning where Z increments), apply them within 48 hours of publication. For minor releases (X.Y), test and deploy within 2 weeks. Given that 2025 saw 16 CVEs and 2026 has already seen 6 in Q1, the cadence of Django security releases is roughly one every 4-6 weeks. Automating your monitoring so you're alerted immediately is the most reliable approach.
CVE-2025-64459 had a CVSS of 9.1 — is it still exploitable?
CVE-2025-64459 was patched in Django 5.2.8, 5.1.14, and 4.2.26 (released November 2025). If you've updated Django since then, you're protected. However, a public proof-of-concept exists on GitHub, which means any application still running a vulnerable version is at immediate risk. This CVE is one of the strongest arguments for automated dependency monitoring — it was exploitable for weeks before many teams applied the patch.
Le 3 fevrier 2026, l'equipe securite Django a publie l'une des plus importantes releases de securite de l'histoire du framework : 6 CVE corriges simultanement dans toutes les versions maintenues (4.2, 5.2 et 6.0). Trois de ces CVE sont des injections SQL de severite HIGH — ce qui signifie qu'un attaquant pourrait potentiellement lire, modifier ou supprimer des donnees dans votre base de donnees sans authentification.
Un mois plus tard, le 4 mars 2026, Django a publie une autre release de securite couvrant 2 CVE supplementaires. Pour les equipes Python utilisant Django comme framework central, 2026 a ete une annee exigeante en termes de suivi des correctifs. Cet article passe en revue chaque CVE publie a ce jour, les patterns sous-jacents qui les causent, et la methode la plus fiable pour ne jamais executer une version vulnerable.
La release Django de fevrier 2026 : 3 injections SQL en une seule mise a jour
La release du 3 fevrier — qui a mis Django en versions 6.0.2, 5.2.11 et 4.2.28 — a corrige un cluster de vulnerabilites d'injection SQL toutes enracinees dans le meme schema de code : des entrees non sanitisees atteignant la couche de requetes a travers les internes de l'ORM Django.
| CVE | Severite | Composant | Vecteur d'attaque |
|---|---|---|---|
CVE-2026-1207 |
HIGH | PostGIS RasterField |
Index de bande non sanitise utilise comme parametre SQL — permet une injection SQL arbitraire via les requetes raster GIS. Activement exploitee depuis le 26 fev 2026. |
CVE-2026-1287 |
HIGH | FilteredRelation + **kwargs |
Caracteres de controle dans les noms d'alias de colonnes contournent la sanitization dans les expressions FilteredRelation |
CVE-2026-1312 |
HIGH | QuerySet.order_by() + FilteredRelation |
Caracteres point (.) dans les alias passes a order_by() permettent une injection SQL arbitraire |
CVE-2026-25673 |
MEDIUM — CVSS 6.3 | Normalisation Unicode URLField |
Une entree Unicode specialement forgee sur Windows declenche un deni de service via une boucle de normalisation infinie |
CVE-2026-25674 |
LOW | Permissions fichiers/repertoires | Les fichiers et repertoires nouvellement crees peuvent recevoir des permissions incorrectes dans certaines configurations |
Toutes ces vulnerabilites affectent Django 4.2 avant 4.2.28, 5.2 avant 5.2.11, et 6.0 avant 6.0.2. Si vous utilisez une version plus ancienne, votre application est exposee a ces vecteurs d'attaque en ce moment meme.
requirements.txt, Pipfile.lock ou poetry.lock fixe Django en dessous de 4.2.28 / 5.2.11 / 6.0.2, mettez a jour immediatement. Les vulnerabilites d'injection SQL (CVE-2026-1207, CVE-2026-1287, CVE-2026-1312) peuvent mener a une compromission complete de la base de donnees sans authentification.
Le pattern FilteredRelation : une classe de vulnerabilites recurrente
Ce qui rend ce lot de CVE particulierement notable, c'est qu'il ne s'agit pas d'une nouvelle surface d'attaque — c'est un pattern recurrent. La racine de CVE-2026-1287 et CVE-2026-1312 remonte a CVE-2022-28346, une injection SQL via le filtrage **kwargs decouverte en avril 2022. Malgre le correctif original, des chemins de code subsequents dans FilteredRelation et order_by() contenaient le meme pattern d'entree non sanitisee.
L'equipe securite Django l'a elle-meme reconnu dans un billet de blog publie le lendemain de la release :
"Presque chaque rapport maintenant est une variation d'une vulnerabilite anterieure. Au lieu de decouvrir de nouvelles classes de problemes, ces rapports explorent comment un pattern sous-jacent d'un avis recent peut apparaitre dans un chemin de code similaire." — Django Security Team, 4 fevrier 2026
L'equipe a egalement note quelque chose de nouveau : les attaquants et chercheurs utilisent de plus en plus des grands modeles de langage pour generer des variations de patterns CVE connus dans des chemins de code similaires. Cela signifie que la velocite de decouverte de vulnerabilites va probablement augmenter — rendant le monitoring continu des dependances plus critique que jamais.
Le pire CVE Django de ces dernieres annees : CVE-2025-64459 (CVSS 9.1)
Alors que le lot de fevrier 2026 a attire l'attention par son volume, 2025 a produit ce qui est considere comme le CVE Django le plus severe depuis des annees : CVE-2025-64459, note CVSS 9.1 CRITIQUE.
Publie le 6 novembre 2025, il affectait les objets Q() de Django et QuerySet.filter() via le parametre _connector. Le vecteur d'attaque etait particulierement alarmant : aucune authentification requise, faible complexite d'attaque, exposition complete des donnees. Un attaquant non authentifie pouvait forger une requete qui contourne l'autorisation, exfiltre des donnees ou eleve ses privileges — le tout via une simple requete HTTP.
Q() et QuerySet.filter() avec le parametre _connector. Corrige dans Django 5.2.8, 5.1.14 et 4.2.26. Proof-of-concept public disponible sur GitHub. Aucune authentification requise pour l'exploitation.
Historique complet des CVE Django : 2025 a ete la pire annee
En remettant 2026 dans son contexte, les donnees historiques de l'archive officielle Django et de CVEDetails revelent une tendance claire : la decouverte de vulnerabilites s'accelere.
Les 16 CVE de 2025 representent un record absolu pour le framework Django — presque le double des 9 CVE de 2024. Avec 6 CVE deja publies en T1 2026, la trajectoire sugge que 2026 pourrait etre tout aussi exigeante.
Pourquoi Django continue-t-il a voir des vulnerabilites d'injection SQL ?
Django est largement reconnu pour son ORM, cense abstraire le SQL brut et prevenir les injections par defaut. Alors pourquoi ces vulnerabilites continuent-elles d'apparaitre ?
La reponse reside dans l'interface entre les donnees controlees par l'utilisateur et les internes de l'ORM. Quand vous utilisez des fonctionnalites comme FilteredRelation, RawSQL, order_by() avec des arguments dynamiques, ou des requetes PostGIS geo-spatiales, vous travaillez avec une interface plus complexe qu'un simple Model.objects.filter(field=value). Ces API avancees manipulent souvent des noms de colonnes, des chaines d'alias ou des parametres d'index en tant que chaines brutes avant qu'ils n'atteignent la couche de parametrisation SQL.
# Pattern a risque — **kwargs dynamiques avec FilteredRelation
# CVE-2026-1287 : les caracteres de controle dans l'alias contournent la sanitization
queryset = MonModel.objects.annotate(
related=FilteredRelation('cle_etrangere', condition=Q(**{entree_utilisateur: valeur}))
)
# Pattern a risque — order_by dynamique avec alias contenant un point
# CVE-2026-1312
queryset = MonModel.objects.order_by(f'related.{champ_utilisateur}')
# Pattern securise — liste blanche des noms de champs
CHAMPS_AUTORISES = {'nom', 'cree_le', 'statut'}
champ_tri = request.GET.get('tri', 'cree_le')
if champ_tri not in CHAMPS_AUTORISES:
champ_tri = 'cree_le'
queryset = MonModel.objects.order_by(champ_tri)
9 bonnes pratiques de securite pour les applications Django en 2026
Au-dela de maintenir Django lui-meme a jour, les pratiques suivantes reduisent significativement votre surface d'attaque :
- Mettez a jour vers Django 6.0.2 / 5.2.11 / 4.2.28 immediatement. Ces versions contiennent les correctifs pour tous les CVE du T1 2026. Verifiez votre version fixee dans
requirements.txtoupoetry.lock. - Ne passez jamais d'entrees utilisateur brutes comme noms de champs dans les filtres
**kwargs. C'est la cause premiere de CVE-2022-28346, CVE-2026-1287 et CVE-2026-1312. Mettez en liste blanche tous les noms de champs autorises avant de les utiliser dans les appels ORM. - Evitez
RawSQL,extra()etcursor.execute()avec des donnees utilisateur. Utilisez plutot les requetes parametrisees de l'ORM Django — elles gerent l'echappement automatiquement. - Definissez
DEBUG = Falseen production. Le mode debug expose des tracebacks complets qui revelent votre modele de donnees, les requetes SQL et les variables d'environnement a quiconque declenche une erreur. - Stockez
SECRET_KEYdans une variable d'environnement, jamais danssettings.py. Utilisezdjango-environouos.environde Python. - Activez
SecurityMiddlewareet configurez HTTPS. Cela couvre HSTS, les en-tetes XSS et la protection contre le sniffing de type de contenu en un seul middleware. - Utilisez
django-axesoudjango_ratelimitpour la protection contre le brute-force. L'authentification integree de Django ne limite pas le debit des tentatives de connexion. - Monitorez les dependances transitives, pas seulement Django lui-meme. 25% des equipes ne suivent que les dependances directes (Snyk 2024) — une dependance transitive vulnerable comme
urllib3oucryptographyest tout aussi dangereuse. - Automatisez votre monitoring CVE. Lancer
pip auditen CI detecte les vulnerabilites au moment du deploiement, mais pas 3 semaines plus tard quand un nouveau CVE arrive. Utilisez un outil de monitoring continu qui vous alerte en temps reel.
Questions frequentes
Quelles versions de Django sont affectees par les CVE de fevrier 2026 ?
Toutes les versions Django inferieures a 4.2.28, 5.2.11 et 6.0.2 sont affectees par CVE-2026-1207, CVE-2026-1287 et CVE-2026-1312. Si vous utilisez Django 3.x ou toute version 4.x inferieure a 4.2.28, ces versions sont egalement dans la plage vulnerable, et vous devriez migrer immediatement vers une branche maintenue. Django 3.x et 4.0/4.1 ne recevant plus de mises a jour de securite.
CVE-2026-1312 est-il exploitable sans authentification ?
Cela depend de la maniere dont votre application utilise QuerySet.order_by() avec des alias FilteredRelation. Si des entrees controlees par l'utilisateur sont passees en parametre de tri ou comme nom d'alias, l'exploitation peut se faire sans aucune authentification. L'equipe securite Django le classe avec une severite HIGH avec potentiel d'execution SQL arbitraire.
Comment verifier si ma version Django a des CVE connus maintenant ?
Lancez pip audit dans l'environnement virtuel de votre projet pour scanner contre la base OSV. Pour un monitoring continu (alertes quand de nouveaux CVE sont publies correspondant a votre version actuelle), vous pouvez importer votre requirements.txt ou poetry.lock dans CVE OptiBot — le scanner surveille quotidiennement et vous envoie un email quand de nouvelles vulnerabilites correspondent a votre stack.
L'ORM Django me protege-t-il par defaut contre les injections SQL ?
Pour les operations queryset standard comme Model.objects.filter(field=value), oui — Django utilise des requetes parametrisees qui previennent les injections. Les vulnerabilites de T1 2026 (et historiquement) surviennent specifiquement dans les fonctionnalites avancees de l'ORM comme FilteredRelation, RawSQL, order_by() avec des arguments dynamiques, et les requetes PostGIS. Evitez de passer des donnees controlees par l'utilisateur comme noms de champs ou alias dans ces API.
Quelle est la frequence recommandee de mise a jour de Django en production ?
Pour les releases de securite (versionnage X.Y.Z ou Z incremente), appliquez-les dans les 48 heures suivant leur publication. Pour les releases mineures (X.Y), testez et deployez sous 2 semaines. Etant donne que 2025 a vu 16 CVE et 2026 en a deja 6 en T1, la cadence des releases de securite Django est d'environ une toutes les 4 a 6 semaines. Automatiser votre monitoring pour etre alerte immediatement est l'approche la plus fiable.
CVE-2025-64459 avait un CVSS de 9.1 — est-il toujours exploitable ?
CVE-2025-64459 a ete corrige dans Django 5.2.8, 5.1.14 et 4.2.26 (publie en novembre 2025). Si vous avez mis a jour Django depuis lors, vous etes protege. Cependant, un proof-of-concept public existe sur GitHub, ce qui signifie que toute application executant encore une version vulnerable est en danger immediat. Ce CVE est l'un des arguments les plus forts pour le monitoring automatise des dependances — il etait exploitable pendant des semaines avant que de nombreuses equipes n'appliquent le correctif.