djangoproject Django GeoDjango Spatial Lookups Enable Server-Side File Writes and SSRF

Note: This data is for reference and cybersecurity research purposes only.CyStack advises users not to use this information for unlawful purposes.

What is CVE-2026-15307?

CVE-2026-15307 is a vulnerability classified as External Control of File Name or Path and Server-Side Request Forgery (SSRF), affecting Django (affected versions: 6.0 – < 6.0.8 and 5.2 – < 5.2.17). This vulnerability is rated High, with a CVSS score of 8.7. Current sources do not report this vulnerability as exploited.

Overview

Original source data

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.

Affected products and scope

  • Django 6.0 before 6.0.8 is marked affected.
  • Django 5.2 before 5.2.17 is marked affected.
  • Earlier unsupported Django series, including 5.1.x, 5.0.x, and 4.2.x, were not evaluated and may also be affected.
  • The vendor advisory states that patches were applied to the main, 6.1, 6.0, and 5.2 branches. The normalized record establishes exact affected boundaries only for 5.2 and 6.0, so it does not establish a specific released fix boundary for main or 6.1.

Technical details

GeoDjango processes the right-hand side of a spatial lookup by attempting to parse the value as a raster through the django.contrib.gis.gdal.GDALRaster constructor before handling it as a geometry. A dict, or a str containing its JSON representation, can cause GDAL to open a raster in write mode even though the constructor defaults to write=False, allowing a file with attacker-controlled name and contents to be written through a file-backed GDAL driver. Other str values are treated as datasources and can trigger an outbound network request through a GDAL virtual filesystem handler. This path applies to values used in spatial lookups against GeometryField or RasterField, including untrusted input from filters in the Django admin changelist. A staff user with view permission on a registered admin model containing a spatial field can reach this path when the application permits spatial filtering; the exact GDAL driver, target file location, network destination, and whether the application later imports the file depend on deployment-specific behavior.

Exploitability

The flaw is network-reachable when an application exposes spatial lookups, particularly through Django admin changelist filtering. The documented precondition is low-level access, exemplified by a staff user with view permission on a registered model containing a spatial field; no additional victim interaction is required after the lookup is submitted. The processing path has low complexity because attacker-controlled values are passed into raster parsing. The supplied record marks public_exploit as false and does not identify a known exploited status; this does not prove that exploitation has never occurred.

Technical impact

The direct technical outcome is that an attacker-controlled spatial lookup value can cause GDAL to write a file or make a network request on behalf of the Django process. File-write scope is constrained by the GDAL driver and process permissions, but the vulnerable path permits attacker-chosen file names and contents. The outbound request path can create SSRF and expose the server's ability to reach internal or external services, depending on the environment. If a written file is placed where the application automatically loads or executes it, remote code execution is possible, but it is not guaranteed in every deployment. Exploitation still requires suitable access to the endpoint or admin lookup and does not automatically bypass the process's permission boundaries.

Business impact

The flaw can create or modify server-side files with attacker-controlled contents, affecting application and system integrity. If the written file lands where the application later imports or executes it, the consequence could expand to remote code execution with the Django process's privileges. The SSRF path can cause the server to contact destinations that an external user cannot reach directly, depending on network policy and the GDAL virtual filesystem handler. Unexpected requests or file activity could also disrupt service if configuration, data, or other required application resources are affected. The record does not identify a specific compromise, victim, or campaign.

Remediation

  1. For the Django 6.0 branch, upgrade to Django 6.0.8.
  2. For the Django 5.2 branch, upgrade to Django 5.2.17.
  3. If running an unsupported series, treat it as potentially affected and move to a supported branch; this record does not provide an exact fixed-version boundary for those series.
  4. Validate all untrusted data before using it in a spatial lookup. Do not pass a dict, JSON string, or arbitrary string directly to a lookup. If the application intentionally needs to use such a raster value in a lookup, construct GDALRaster deliberately after controlling and validating the source.
  5. Test custom lookups and admin functionality after upgrading because rejecting raster-like strings and dict values is a backward-incompatible change. Assigning these types to model fields is a separate behavior and is not a fix for the vulnerable lookup path.

Detection

  1. Inventory Django versions and identify deployments using GeoDjango, especially models with GeometryField or RasterField.
  2. Review models registered in Django admin and any changelist filters or custom lookups that allow staff users to supply spatial values through requests.
  3. Search application code for paths that pass a dict, JSON string, or other untrusted string directly into a spatial lookup instead of validating and converting it first.
  4. After upgrading, test these lookup inputs and confirm that they are rejected before reaching GDALRaster; model-field assignment is a separate path and should not be used as evidence that lookups are safe.
  5. As precautionary monitoring, review outbound network activity and file creation or modification by the Django process. Treat unusual activity as an investigation lead, not as a confirmed indicator for this vulnerability.
Sources (24)
Learn more

Run an in-depth assessment with complete web risk management

CyStack VulnScan continuously discovers assets, validates vulnerabilities, and helps security teams prioritize remediation across the organization.