Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-15307

CVE-2026-15307: Django GeoDjango RCE Vulnerability

CVE-2026-15307 is a remote code execution vulnerability in Django GeoDjango that allows attackers to write malicious files and trigger code execution. This article covers technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-15307 Overview

CVE-2026-15307 affects 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. A dict or JSON string is opened in write mode, allowing an attacker to write a file with a chosen name and contents through a file-backed GDAL driver. Any other string is treated as a datasource, enabling outbound network requests through a GDAL virtual filesystem handler.

Critical Impact

Writing a file to a location later imported by the application can result in remote code execution. Authenticated staff users with view permission on spatial models can trigger the flaw through the Django admin changelist query string.

Affected Products

  • Django 5.2 versions before 5.2.17
  • Django 6.0 versions before 6.0.8
  • Unsupported Django series (5.1.x, 5.0.x, 4.2.x) were not evaluated and may also be affected

Discovery Timeline

  • Vulnerability reported by Bence Nagy, localhost-detect, and kimchunbok_
  • 2026-08-04 - Django security release published and CVE-2026-15307 published to NVD
  • 2026-08-05 - Last updated in NVD database

Technical Details for CVE-2026-15307

Vulnerability Analysis

The flaw resides in GeoDjango's spatial lookup handling under django.contrib.gis. When a value is filtered against a GeometryField or RasterField, Django optimistically passes it to GDALRaster to check whether it represents a raster. This constructor accepts multiple input types with different semantics. A Python dict, or a str holding its JSON representation, causes GDAL to open the datasource in write mode regardless of the constructor's write=False default. An attacker can supply JSON specifying a driver, a filename, and payload contents, causing GDAL to create that file on disk.

A plain str input is instead treated as a datasource path. GDAL resolves prefixes such as /vsicurl/ and /vsis3/, triggering outbound network requests through virtual filesystem handlers. The vulnerability is classified under CWE-73: External Control of File Name or Path.

Root Cause

GeoDjango calls GDALRaster(value) on lookup inputs without validating the type or contents. The default write=False flag is overridden when the input is a dict or JSON, so file-backed GDAL drivers create attacker-controlled files. String inputs fall through to GDAL's virtual filesystem layer, which supports network transports.

Attack Vector

Any code path that reaches a spatial lookup with untrusted input is exploitable. The advisory specifically calls out the Django admin changelist query string, which a staff user with only view permission on a spatial model can manipulate. Writing a .py file, template, or configuration into a directory later imported or executed by the application yields remote code execution.

python
# Django security patch introducing DisallowedRasterLookup
# Source: https://github.com/django/django/commit/115ffd0463a765ab1cc93de18e94b5459b8a300e
from django.contrib.gis.gdal.srs import SpatialReference, SRSException
from django.contrib.gis.geometry import json_regex
from django.core.exceptions import SuspiciousOperation
from django.utils.encoding import force_bytes, force_str
from django.utils.functional import cached_property


class DisallowedRasterLookup(SuspiciousOperation):
    """
    Types that force GDALRaster to open in write mode (dict) or values that
    could be virtual filesystem paths (str) are not allowed in lookup contexts.
    Instead, wrap values in GDALRaster explicitly.
    """

The patch adds a DisallowedRasterLookup exception (a SuspiciousOperation subclass) and blocks dict inputs and strings matching the VSI_FILESYSTEM_PREFIX in spatial lookup code paths.

Detection Methods for CVE-2026-15307

Indicators of Compromise

  • Unexpected files created in application-writable directories, especially .py, .pyc, or template files under sys.path-reachable paths
  • Django admin changelist requests containing JSON payloads with driver, name, or datapointer keys in spatial field filter parameters
  • Query-string values against GeometryField or RasterField filters that begin with /vsicurl/, /vsis3/, /vsigs/, or other GDAL VSI prefixes
  • Outbound network connections initiated by the Django process to domains not tied to normal application behavior

Detection Strategies

  • Search Django access logs for admin URLs containing spatial field lookups with {, }, or /vsi sequences in filter parameters
  • Instrument or wrap django.contrib.gis.gdal.GDALRaster calls to log the input type and value during audit periods
  • Correlate staff-user admin activity with file-creation events under the application's working directory

Monitoring Recommendations

  • Alert on SuspiciousOperation exceptions in Django application logs after patching, as they may indicate exploitation attempts against the new DisallowedRasterLookup guard
  • Monitor GeoDjango-enabled hosts for new files written to MEDIA_ROOT, STATIC_ROOT, or any directory listed in sys.path
  • Track egress connections from Python worker processes to unexpected destinations, which may indicate abuse of GDAL VSI handlers

How to Mitigate CVE-2026-15307

Immediate Actions Required

  • Upgrade Django to version 5.2.17 or 6.0.8 as published in the Django security releases
  • Review staff-user permissions on models exposing GeometryField or RasterField in the Django admin and revoke unnecessary view access
  • Audit filesystem locations writable by the Django process for unexpected files created since GeoDjango was enabled

Patch Information

Django released fixes across supported branches in commits 115ffd0 (5.2.x), 208f80c (6.0.x), and 39b3e2d (6.1.x). The patches introduce DisallowedRasterLookup and reject dict inputs and strings with GDAL VSI prefixes in spatial lookup contexts. Applications relying on raster values in lookups must now wrap them explicitly in GDALRaster.

Workarounds

  • If immediate patching is not possible, remove or restrict Django admin access to models that expose GeometryField or RasterField filters
  • Place a web application firewall rule in front of Django admin URLs that blocks query strings containing /vsi prefixes or JSON-encoded values in spatial field parameters
  • Run the Django application process under a minimal filesystem sandbox that prevents writes outside a dedicated data directory not listed in sys.path
bash
# Upgrade Django to a patched release
pip install --upgrade "Django>=5.2.17,<6.0"   # for 5.2.x deployments
pip install --upgrade "Django>=6.0.8"         # for 6.0.x deployments

# Verify the installed version
python -c "import django; print(django.get_version())"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.