See how django compares to other vendors in security performance
An issue was discovered in Django 4.2 before 4.2.25, 5.1 before 5.1.13, and 5.2 before 5.2.7. QuerySet.annotate(), QuerySet.alias(), QuerySet.aggregate(), and QuerySet.extra() are subject to SQL injection in column aliases, when using a suitably crafted dictionary, with dictionary expansion, as the kwargs passed to these methods (on MySQL and MariaDB).
An issue was discovered in Django 4.2 before 4.2.25, 5.1 before 5.1.13, and 5.2 before 5.2.7. The django.utils.archive.extract() function, used by the "startapp --template" and "startproject --template" commands, allows partial directory traversal via an archive with file paths sharing a common prefix with the target directory.
An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8. GeoDjango's django.contrib.gis.geos.GEOSGeometry is subject to a potential denial-of-service when parsing deeply nested GEOMETRYCOLLECTION objects supplied as well-known text (WKT), well-known binary (WKB), or hex-encoded WKB, which triggers unbounded recursion and a segmentation fault in the underlying GEOS library. Spatial field lookups and the django.contrib.gis.forms.GeometryField form field are also affected. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Andrew MacPherson and kimchunbok for reporting this issue.
An issue was discovered in Django 6.1 before 6.1.2, 6.0 before 6.0.9, and 5.2 before 5.2.18. django.utils.translation.getsupportedlanguagevariant() is subject to a potential denial-of-service attack when processing many distinct, very long language codes, which are retained as keys in an in-memory cache and consume process memory. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Gleb Lizunov for reporting this issue.
An issue was discovered in Django 6.1 before 6.1.2, 6.0 before 6.0.9, and 5.2 before 5.2.18. django.utils.http.parseheaderparameters() was subject to a potential denial-of-service attack due to quadratic time complexity when parsing a value with many separators inside a quoted parameter. An unauthenticated request could reach this parsing through headers such as Accept or Content-Type, for instance via the content negotiation performed by HttpRequest.accepts(). The per-call length limit does not bound the combined size of repeated headers. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Jisung Chae for reporting this issue.
An issue was discovered in Django 6.1 before 6.1.2, 6.0 before 6.0.9, and 5.2 before 5.2.18. An incomplete fix for CVE-2026-15307 in Django spatial lookups allows an attacker who can supply bytes values to cause the Django process to make network requests via a crafted VRT document referencing an external raster source. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank sicksec for reporting this issue.
An issue was discovered in Django 6.1 before 6.1.2, 6.0 before 6.0.9, and 5.2 before 5.2.18. django.forms.models.BaseModelFormSet.saveexistingobjects() used the presence of a primary key on a submitted form's instance as evidence that the instance belonged to the formset's limiting queryset. An object outside that queryset is represented by a newly constructed instance whose primary key can still be populated from submitted data when the model's primary key is a field accepted by the form, such as a OneToOneField or parent link used as the primary key of an inline formset's model, or a natural or UUID primary key included in the form's fields. This allows an authenticated user permitted to submit such a formset to delete rows outside the limiting queryset, without any permission on the targeted object, via forged management-form data marking an out-of-queryset object for deletion. Models using the default AutoField primary key are not affected. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Seonggwon Yoon for reporting this issue.
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28.
ASGIRequest allows a remote attacker to cause a potential denial-of-service via a crafted request with multiple duplicate headers. 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 Jiyong Yang for reporting this issue.
DjangoCRM ships with its Django SECRETKEY hardcoded directly in the committed webcrm/settings.py rather than read from an environment variable. Since this key is used for session signing, CSRF token generation, and password reset tokens, anyone who reads the public repository can forge valid session cookies (including for the superadmin account), forge CSRF tokens, and forge password reset tokens, achieving full account takeover.
An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8. GeoDjango spatial lookups optimistically parse the right-hand-side value as a raster by passing it to the django.contrib.gis.gdal.GDALRaster constructor. Any value used in a spatial lookup against a GeometryField or RasterField reaches this constructor, including untrusted input, for example a spatial-field filter submitted through the Django admin changelist query string by a staff user with view permission. A dict, or a str holding its JSON representation, is opened in write mode regardless of the constructor's write=False default, allowing a file with an attacker-chosen name and contents to be written through a file-backed GDAL driver. Any other str is treated as a datasource, allowing an outbound network request through a GDAL virtual filesystem handler. Writing a file to a location later imported by the application can result in remote code execution. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Bence Nagy, localhost-detect, and kimchunbok for reporting this issue.
daphne before 4.2.2 did not pass maxFramePayloadSize or maxMessagePayloadSize to Autobahn's WebSocketServerFactory. Because Autobahn defaults both values to 0 (unlimited), an unauthenticated remote attacker could send arbitrarily large WebSocket messages or frames, causing excessive memory consumption and a denial of service.
An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8. GeoDjango spatial lookups optimistically parse the right-hand-side value as a raster by passing it to the django.contrib.gis.gdal.GDALRaster constructor. Any value used in a spatial lookup against a GeometryField or RasterField reaches this constructor, including untrusted input, for example a spatial-field filter submitted through the Django admin changelist query string by a staff user with view permission. A dict, or a str holding its JSON representation, is opened in write mode regardless of the constructor's write=False default, allowing a file with an attacker-chosen name and contents to be written through a file-backed GDAL driver. Any other str is treated as a datasource, allowing an outbound network request through a GDAL virtual filesystem handler. Writing a file to a location later imported by the application can result in remote code execution. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Bence Nagy, localhost-detect, and kimchunbok for reporting this issue.
An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8. django.utils.translation.checkforlanguage() is subject to a potential denial-of-service attack when given many distinct, very long language codes, which are retained as keys in an in-memory cache and consume process memory. Such codes reach the function through the django.views.i18n.setlanguage() view, which is not routed by default. The consumed memory is bounded, since request data is limited by the DATAUPLOADMAXMEMORYSIZE setting (default 2.5 MB) and the cache holds a fixed maximum number of entries. Earlier, unsupported Django series (such as 5.1.x, 5.0.x, and 4.2.x) were not evaluated and may also be affected. Django would like to thank Jaeyoung Jang for reporting this issue.
Django's admin auto-linked URLField values without validating the scheme — a stored javascript: value rendered as a live link. Fixed in 6.0.8 and 5.2.17.
Summary
A Cross-site Scripting (XSS) vulnerability exists in the {% attrs %} template tag of the slippers Django package. When a context variable containing untrusted data is passed to {% attrs %}, the value is interpolated into an HTML attribute string without escaping, allowing an attacker to break out of the attribute context and inject arbitrary HTML or JavaScript into the rendered page.
Vulnerability details
Root cause
AttrsNode is a custom Node subclass registered via register.tag(). Unlike register.simpletag(), which automatically applies conditionalescape() when autoescape is on, custom Node.render() methods receive no automatic escaping and are fully responsible for sanitising their output. attrstring() fails to do this:
python def attrstring(key: str, value: Any): if isinstance(value, bool): return key if value else "" key = key.replace("", "-") return f'{key}="{value}"' # value is not escaped
Attack scenario
Given a template that uses {% attrs %} with a user-supplied value:
django {% load slippers %} <input {% attrs type placeholder %}>
python render(request, "search.html", {"placeholder": request.GET.get("q", "")})
An attacker crafting a request with q=" onmouseover="alert(document.cookie)" x=" produces:
html <input type="text" placeholder="" onmouseover="alert(document.cookie)" x="">
Impact
Any template that passes values derived from user input, database content, or other untrusted sources to {% attrs %} is vulnerable. Successful exploitation can lead to session hijacking, credential theft, arbitrary actions on behalf of the victim, and page defacement.
Remediation
Replace the f-string in attrstring() with formathtml(), which escapes both key and value:
python from django.utils.html import formathtml
def attrstring(key: str, value: Any): if isinstance(value, bool): return key if value else "" key = key.replace("", "-") return formathtml('{}="{}"', key, value)
Until a patch is available, sanitise untrusted values before passing them to {% attrs %}, for example with django.utils.html.escape() in the view layer.
An issue was discovered in Django 5.2 before 5.2.15 and 6.0 before 6.0.6. django.utils.cache.hasvaryheader() in Django does not strip leading or trailing whitespace from Vary response header values before comparison, which allows remote attackers to read cached responses via requests to URLs whose responses contain whitespace-padded Vary header values. 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 Navid Rezazadeh for reporting this issue.
An issue was discovered in Django 5.2 before 5.2.15 and 6.0 before 6.0.6. django.middleware.cache.UpdateCacheMiddleware in Django does not match Cache-Control response directives case-insensitively, which allows remote attackers to read responses that were incorrectly cached because their Cache-Control directives used uppercase or mixed-case values. 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 Ahmed Badawe for reporting this issue.
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. Raster lookups on RasterField (only implemented on PostGIS) allows remote attackers to inject SQL via the band index parameter. 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 Tarek Nakkouch for reporting this issue.
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. .QuerySet.orderby() is subject to SQL injection in column aliases containing periods when the same alias is, using a suitably crafted dictionary, with dictionary expansion, used in FilteredRelation. 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.
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. django.utils.text.Truncator.chars() and Truncator.words() methods (with html=True) and the truncatecharshtml and truncatewordshtml template filters allow a remote attacker to cause a potential denial-of-service via crafted inputs containing a large number of unmatched HTML end tags. 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 Seokchan Yoon for reporting this issue.
An issue was discovered in Django 5.1 before 5.1.5, 5.0 before 5.0.11, and 4.2 before 4.2.18. Lack of upper-bound limit enforcement in strings passed when performing IPv6 validation could lead to a potential denial-of-service attack. The undocumented and private functions cleanipv6address and isvalidipv6address are vulnerable, as is the django.forms.GenericIPAddressField form field. (The django.db.models.GenericIPAddressField model field is not affected.)
An issue was discovered in Django 5.1 before 5.1.7, 5.0 before 5.0.13, and 4.2 before 4.2.20. The django.utils.text.wrap() method and wordwrap template filter are subject to a potential denial-of-service attack when used with very long strings.
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. ASGIRequest allows a remote attacker to cause a potential denial-of-service via a crafted request with multiple duplicate headers. 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 Jiyong Yang for reporting this issue.
An issue was discovered in 6.0 before 6.0.3, 5.2 before 5.2.12, and 4.2 before 4.2.29. URLField.topython() in Django calls urllib.parse.urlsplit(), which performs NFKC normalization on Windows that is disproportionately slow for certain Unicode characters, allowing a remote attacker to cause denial of service via large URL inputs containing these characters. 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 Seokchan Yoon for reporting this issue.
An issue was discovered in Django 6.0 before 6.0.7 and 5.2 before 5.2.16. UpdateCacheMiddleware and the cachepage() decorator cache responses that vary on cookies when the incoming request carries unrelated cookies, which allows remote attackers to read private data from the shared cache. 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 Chris Whyland for reporting this issue.
An issue was discovered in Django 6.0 before 6.0.7 and 5.2 before 5.2.16. django.contrib.gis.gdal.GDALRaster over-reads its in-memory buffer when constructed from a bytes object, which can disclose adjacent memory or cause service degradation via a potential segmentation fault when the vsibuffer property is accessed. 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 Bence Nagy for reporting this issue.
An issue was discovered in Django 6.0 before 6.0.7 and 5.2 before 5.2.16. DomainNameValidator does not prohibit newlines in domain names (unless used via a form field, since CharField strips newlines). If an application uses values with newlines in an HTTP response, header injection can occur. Django itself is unaffected because HttpResponse prohibits newlines in HTTP headers. 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 Bence Nagy for reporting this issue.
Announce: https://www.djangoproject.com/weblog/2026/jul/07/security-releases/
CVE JSON Record for CVE-2026-48588: https://www.cve.org/CVERecord?id=CVE-2026-48588
CVE JSON Record for CVE-2026-53877: https://www.cve.org/CVERecord?id=CVE-2026-53877
CVE JSON Record for CVE-2026-53878: https://www.cve.org/CVERecord?id=CVE-2026-53878
In accordance with our security release policy, the Django team is issuing releases for Django 6.0.7 and Django 5.2.16. These releases address the security issues detailed below. We encourage all users of Django to upgrade as soon as possible.
CVE-2026-48588: Potential exposure of private data via cached Set-Cookie response
django.middleware.cache.UpdateCacheMiddleware and django.views.decorators.cache.cachepage avoided caching responses that set a cookie while varying on Cookie only when the incoming request contained no cookies at all. When the request already carried an unrelated cookie (such as a language or theme preference cookie), the protection did not apply, allowing a response that sets a session or other sensitive cookie to be stored in Django's shared cache.
This issue has severity "low" according to the Django security policy.
Thanks to Chris Whyland for the report.
CVE-2026-53877: Heap buffer over-read in GDALRaster
When django.contrib.gis.gdal.GDALRaster was instantiated with a bytes object representing a raster file, the vsibuffer property could over-read the allocated buffer by approximately 32 bytes. This could result in information disclosure of adjacent heap memory or, in rare cases, a segmentation fault. Only rasters stored in GDAL's virtual filesystem were affected.
This issue has severity "low" according to the Django security policy.
Thanks to Bence Nagy for the report.
CVE-2026-53878: Header injection possibility since DomainNameValidator accepted newlines in input
django.core.validators.DomainNameValidator accepted newlines in domain names. If such values were included in HTTP responses, header injection attacks were possible. Django itself wasn't vulnerable because HttpResponse prohibits newlines in HTTP headers.
The vulnerability only affected uses of DomainNameValidator outside Django form fields, as CharField strips newlines by default.
This issue has severity "low" according to the Django security policy.
Thanks to Bence Nagy for the report.
Affected supported versions
Django main Django 6.1 (currently at beta status) Django 6.0 Django 5.2
Resolution
Patches to resolve the issue have been applied to Django's main, 6.1 (currently at beta status), 6.0, and 5.2 branches. The patches may be obtained from the following changesets.
CVE-2026-48588: Potential exposure of private data via cached Set-Cookie response
On the main branch On the 6.1 branch On the 6.0 branch On the 5.2 branch
CVE-2026-53877: Heap buffer over-read in GDALRaster
On the main branch On the 6.1 branch On the 6.0 branch On the 5.2 branch
CVE-2026-53878: Header injection possibility since DomainNameValidator accepted newlines in input
On the main branch On the 6.1 branch On the 6.0 branch On the 5.2 branch
The following releases have been issued
Django 6.0.7 (tarball | checksums) Django 5.2.16 (tarball | checksums)
The PGP key ID used for this release is Jacob Walls: 131403F4D16D8DC7
General notes regarding security reporting
As always, we ask that potential security issues be reported via private email to security () djangoproject com, and not via Django's Trac instance, nor via the Django Forum. Please see our security policies for further information.
An issue was discovered in 6.0 before 6.0.5 and 5.2 before 5.2.14. django.middleware.cache.UpdateCacheMiddleware erroneously caches requests where the Vary header contained an asterisk (''). This can lead to private data being stored and served. 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 Ahmad Sadeddin for reporting this issue.