Injection

Injection in Django: remediation guide [Month Year] [CVE-2007-0405]

[Fixed month year] Updated CVE-2007-0405

Overview

Injection vulnerabilities in Django historically include flaws in the authentication flow where user identity could be hijacked across requests. CVE-2007-0405 describes a bug in Django 0.95\'s LazyUser class within the AuthenticationMiddleware where the current username could be cached globally rather than per-request, allowing a remote authenticated user to gain the privileges of another user. This kind of cross-request state can persist in the process and leak authentication information from one request to the next, creating a route for privilege escalation in a multi-user deployment.

Affected Versions

Django 0.95 and earlier; patched in later releases

Code Fix Example

Django API Security Remediation
import sys

# Minimal simulation objects to illustrate the vulnerability and fix
class User:
    def __init__(self, username, is_privileged=False):
        self.username = username
        self.is_privileged = is_privileged

class Session(dict):
    @property
    def session_key(self):
        return self.get('session_key', None)

class Request:
    def __init__(self, user, session_key):
        self.user = user
        self.session = Session({'session_key': session_key})

# Vulnerable pattern (global cache across requests)
class LazyUserVuln:
    _cached_username = None  # global across requests (bad)

    def __init__(self, request):
        self.request = request

    @property
    def username(self):
        if LazyUserVuln._cached_username is not None:
            return LazyUserVuln._cached_username
        LazyUserVuln._cached_username = self.request.user.username
        return LazyUserVuln._cached_username


def vulnerable_demo():
    admin = User('admin', True)
    guest = User('guest', False)
    req1 = Request(admin, 'sessA')
    req2 = Request(guest, 'sessB')

    u1 = LazyUserVuln(req1).username  # caches 'admin'
    u2 = LazyUserVuln(req2).username  # incorrectly returns 'admin' due to global cache
    print('Vulnerable pattern results -> u1:', u1, ' u2:', u2)

# Fixed pattern (per-request cache, not global)
class LazyUserFixed:
    def __init__(self, request):
        self.request = request
        self._cached_username = None

    @property
    def username(self):
        if self._cached_username is not None:
            return self._cached_username
        self._cached_username = self.request.user.username
        return self._cached_username


def fixed_demo():
    admin = User('admin', True)
    guest = User('guest', False)
    req1 = Request(admin, 'sessA')
    req2 = Request(guest, 'sessB')

    v1 = LazyUserFixed(req1).username  # 'admin'
    v2 = LazyUserFixed(req2).username  # 'guest'
    print('Fixed pattern results -> v1:', v1, ' v2:', v2)

if __name__ == '__main__':
    vulnerable_demo()
    fixed_demo()

CVE References

Choose which optional cookies to allow. You can change this any time.