CVE-2024-53908 - Oracle SQL Injection in Django’s HasKey Lookup - What You Need to Know
Recently, a critical security issue was unearthed in the Django framework, specifically tied to the HasKey JSON field lookup when interacting with Oracle databases. This vulnerability—CVE-2024-53908—has raised alarms for developers running Django-powered apps using Oracle as their backend. In this post, I will break down the vulnerability, show a demonstration, discuss who is affected, and give practical advice to stay protected. All explanations will be straightforward, so you don’t need to be a deep security expert to follow along.
Django 4.2 before 4.2.17
The issue affects the rare but direct use of django.db.models.fields.json.HasKey in code when building filters for querysets on Oracle databases. If you let user-controlled data (like search keys) influence the lookup’s *lhs* (left-hand side), attackers can insert malicious SQL into your queries.
> Good news: Most applications, which use jsonfield.has_key lookup via the ORM’s double underscore syntax (like myjsonfield__has_key=…) are NOT affected.
The risk only exists if you directly use the HasKey lookup class in your code with untrusted input on Oracle.
Explaining the Core Issue
Django lets you build powerful query filters. For JSON fields, the HasKey lookup helps you check if a JSON object contains a certain key. In most cases, this is exposed safely at the ORM level, like this:
# No risk here, this is safe!
MyModel.objects.filter(my_json_field__has_key="user_id")
But if, instead, you reach for a lower-level API and use HasKey directly, for example
from django.db.models.fields.json import HasKey
from django.db.models import F
user_input_key = request.GET["key"] # Untrusted input!
# This is risky!
MyModel.objects.filter(HasKey(F("my_json_field"), user_input_key))
*If* you pass in user_input_key straight from user data, and your database is Oracle, Django will construct SQL that is not properly escaped, making injection possible.
Say a page lets the user provide the name of a JSON key to filter employees
/api/search?key=name
But if a hacker provides a malicious key
/api/search?key=name) OR 1=1 --
the final SQL could look roughly like this
SELECT * FROM employees WHERE my_json_field ? 'name) OR 1=1 --'
With careless quoting, this could actually break out of the JSON lookup and run attacker-supplied SQL, like OR 1=1, returning all the rows, or worse.
🚨 Unsafe: Direct HasKey With Untrusted Data
from django.db.models.fields.json import HasKey
def my_view(request):
key = request.GET.get("key") # Example: attacker controls this
qs = MyModel.objects.filter(HasKey('my_json_field', key))
# ... use qs
✅ Safe: Using ORM’s Double-Underscore Lookup
def my_view(request):
key = request.GET.get("key")
qs = MyModel.objects.filter(my_json_field__has_key=key)
# ... use qs
The second example is not vulnerable, as Django’s ORM safely escapes the lookup.
Only trusted constants for the lhs value in HasKey
## How To Fix / Protect
Upgrade guide:
https://docs.djangoproject.com/en/stable/releases/
Django Project Security Release:
- https://docs.djangoproject.com/en/dev/releases/security/
- https://groups.google.com/forum/#!topic/django-announce/
CVE Record:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-53908
Source Patch Example:
- https://github.com/django/django/commit/1476ab9f6d8c99e828679a0734d65e266425bbd3
Conclusion
CVE-2024-53908 is a textbook reminder: SQL injection is still a risk if you step off the beaten path, even in mature frameworks. If your Django apps use Oracle and depend on advanced JSON lookup features, check your code and upgrade right away. Stick to safe ORM practices and let Django’s abstractions protect you.
If you want to dive deeper, see the links above and monitor the official Django Security releases.
Timeline
Published on: 12/06/2024 12:15:18 UTC
Last modified on: 12/06/2024 17:15:12 UTC