HIGH memory leakdjangobasic auth

Memory Leak in Django with Basic Auth

Memory Leak in Django with Basic Auth — how this specific combination creates or exposes the vulnerability

A memory leak in a Django service that uses HTTP Basic Authentication can arise when request handling code does not properly release objects created per request. With Basic Auth, the browser sends an Authorization header on every request. Django decodes this header on each request, and if views or middleware allocate data that grows over time—such as accumulating parsed credentials, attaching large objects to the request, or caching user-specific data without cleanup—the process memory footprint can increase steadily under sustained load.

When combined with unauthenticated scanning, middleBrick tests endpoints that accept Basic Auth headers and observes behavior across repeated calls. Repeated calls with slightly varied credentials can expose patterns where per-request allocations are not freed, especially when developers store parsed user information on the request object for convenience. For example, attaching a user object or a large decoded payload to request and failing to rely on short-lived local variables can keep references alive longer than intended. Over time, this leads to increased resident memory, slower garbage collection, and in extreme cases, process restarts or degraded performance.

The risk is compounded when Basic Auth is used without TLS, because middleware may log or inspect headers, and when endpoints return large responses that are cached or accumulated in per-request buffers. middleBrick’s unauthenticated scan can surface these issues by running repeated, parallel checks against the same endpoint, highlighting irregularities in memory-related findings within the Data Exposure and Unsafe Consumption checks.

Basic Auth-Specific Remediation in Django — concrete code fixes

To reduce memory retention when using Basic Auth in Django, ensure that per-request data is kept short-lived and avoid attaching large or long-lived objects to the request. Prefer extracting credentials only when needed and releasing references after use. Below are concrete patterns to follow.

Secure Basic Auth view pattern

Decode credentials inside the view, use them immediately, and avoid storing them or derived objects on the request.

import base64
from django.http import HttpResponse, HttpResponseForbidden
from django.views import View

class SecureBasicAuthView(View):
    def dispatch(self, request, *args, **kwargs):
        auth = request.META.get('HTTP_AUTHORIZATION', '')
        if not auth.startswith('Basic '):
            return HttpResponseForbidden('Unauthorized')
        token = auth.split(' ', 1)[1]
        decoded = base64.b64decode(token).decode('utf-8')
        username, _, password = decoded.partition(':')
        # Validate credentials (e.g., against Django user model or a service)
        if not self.is_valid(username, password):
            return HttpResponseForbidden('Invalid credentials')
        # Do NOT set request.user = custom_object or attach large data
        return super().dispatch(request, *args, **kwargs)

    def is_valid(self, username, password):
        # Replace with secure validation, e.g., constant-time compare
        return username == 'admin' and password == 's3cr3t'

    def get(self, request):
        return HttpResponse('Authenticated OK')

Middleware that avoids request pollution

If you use middleware, keep it lean. Do not attach user instances or large caches to the request; use local variables and return early on failure.

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponseForbidden
import base64

class LightweightBasicAuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        auth = request.META.get('HTTP_AUTHORIZATION', '')
        if not auth.startswith('Basic '):
            return None  # No credentials; let the view handle it
        try:
            token = auth.split(' ', 1)[1]
            decoded = base64.b64decode(token).decode('utf-8')
            username, _, password = decoded.partition(':')
            if not self.is_valid(username, password):
                return HttpResponseForbidden('Unauthorized')
            # Do NOT assign to request.user or request.credentials
        except Exception:
            return HttpResponseForbidden('Bad credentials format')
        return None

    def is_valid(self, username, password):
        # Validate securely; avoid heavy per-request allocations
        return username == 'svc' and password == 'token'

Operational recommendations

  • Always use HTTPS with Basic Auth to prevent credentials from leaking in headers that may be logged.
  • Avoid caching responses that contain Authorization headers or user-specific data unless cache keys are carefully scoped.
  • Monitor memory usage in production; a steady increase in RSS per worker can indicate a leak.
  • Consider migrating to token-based authentication (e.g., JWT in Authorization header) to reduce the frequency of credential parsing and the risk of accidental retention.

Frequently Asked Questions

Can middleBrick detect memory leaks in Django Basic Auth endpoints?
middleBrick runs unauthenticated scans and can surface patterns related to Data Exposure and Unsafe Consumption that may indicate memory issues, but it does not directly measure or report memory leaks. Use application monitoring and profiling tools for in-depth memory analysis.
Does storing parsed credentials on the request object cause memory leaks?
Attaching large or long-lived objects to the request can keep references alive beyond the request lifecycle, contributing to memory retention. Prefer local variables and avoid polluting the request with per-request state that is not needed after the response is generated.