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