Shivasurya on Security | Tech Blog

2 min read Original article ↗

Vulnerability Overview

Yesterday I came across this CVE-2025-64459 and I was bit skeptical about the severity of the issue as it was marked as critical. So I decided to do a deep dive into the issue and see if it was a real issue or not. Turns out it was a real issue only if you’re meeting the following conditions:

  1. You’re using Django Affected versions
    • >= 5.2a1, < 5.2.8
    • >= 5.0a1, < 5.1.14
    • < 4.2.26
  2. Source: request.GET or request.POST dict

  3. Sink: Directly to QuerySet.filter(), QuerySet.exclude(), and QuerySet.get(), and the class Q()

Example

from django.shortcuts import render
from django.db.models import Q
from .models import Post


def post_list(request):
    # Get query parameters directly from GET
    query_params = dict(request.GET.items())

    # Start with empty Q filter
    q_filter = Q(**query_params)

    # Get all posts matching the Q filters
    posts = Post.objects.filter(q_filter)

    return render(request, 'blog/post_list.html', {'posts': posts})

You can control now with query params, http://127.0.0.1:8000/list?status=private&title=<SOMETHING>&_connector=OR

In this way, if the user passes a extra query parameter say _connector with value OR or AND it will be used to connect the filters to run the query. To me atleast this looks like a feature that’s being abused to perform SQL Injection. Q objects build a boolean expression tree for WHERE clauses, with a connector that is either AND or OR. If you don’t specify one, a Q object defaults to the AND connector i.e Q(**query_params) is equivalent to Q(**query_params, _connector='AND'). The fix as per django commit is to practically validates the connector value to be either OR or AND or XOR.

Exploit

Looks like the _connector parameter can be used to inject arbitrary SQL fragment such as OR 1=1 OR.

http://127.0.0.1:8000/list?status=draft&title=My%20First%20Draft%20Posts&_connector=OR%201=1%20OR

CVE-2025-64459

Fix

def __init__(self, *args, _connector=None, _negated=False, **kwargs):
    if _connector not in self.connectors:
        connector_reprs = ", ".join(f"{conn!r}" for conn in self.connectors[1:])
        raise ValueError(
            f"_connector must be one of {connector_reprs}, or None."
        )
    super().__init__(
        children=[*args, *sorted(kwargs.items())],
        connector=_connector,
    )

CVE-2025-64459

Closing Note

Vulnerabilities like these necessitate inter-procedural analysis (aka cross-file data flow analysis) to detect them to prove if the vulnerability is exploitable or not, popularly some vendors refer to this as reachability analysis in supply chain world or taint analysis in codebases. Probably, algorithms like taint analysis using use-def chains (with type-aware object tracking, respecting CFG, context-sensitivity) can reliably detect such vulnerabilities in codebases. And that’s where code-pathfinder is effectively aiming to be at and become sweet spot for such analysis.