HIGH double freedjangohmac signatures

Double Free in Django with Hmac Signatures

Double Free in Django with Hmac Signatures — how this specific combination creates or exposes the vulnerability

In Django, a Double Free risk can arise when HMAC-based signing is used to protect data integrity but the application logic fails to validate signature provenance before processing the payload. HMAC Signatures in Django are commonly implemented via django.core.signing or custom HMAC schemes that sign serialized data (e.g., JSON or pickled structures) and append the signature as a query parameter or header. A Double Free occurs when the same signed token is consumed more than once in a way that causes side effects such as double writes, double charges, or repeated state changes.

Consider a payment flow where a signed token encodes a transaction amount and a user identifier. If the token is verified with HMAC and then processed multiple times due to retries, race conditions, or lack of idempotency checks, the backend may apply the same transaction twice. This is not a cryptographic flaw in HMAC itself (the signature remains valid), but a design flaw where the system does not track token usage. The vulnerability is exposed when the unsigned data derived from the token is re-applied or re-executed, leading to unauthorized operations.

Attackers can exploit this by intercepting a valid signed request and replaying it, or by crafting scenarios where the server re-processes the same signed payload. For example, an unsigned POST body may be combined with a valid HMAC header to trigger duplicate resource creation. Since HMAC only ensures integrity and authenticity, Django developers must add uniqueness constraints, idempotency keys, or transaction deduplication to prevent Double Free conditions. Without these controls, the combination of Hmac Signatures and state-changing operations creates a window for resource exhaustion or inconsistent state.

Hmac Signatures-Specific Remediation in Django — concrete code fixes

Remediation focuses on ensuring each signed payload is consumed at most once and that state changes are idempotent. Use signed tokens with embedded uniqueness (e.g., a UUID or nonce) and enforce one-time validation on the server.

Example 1: Django signing with a nonce and idempotency key

import uuid
import json
from django.core import signing
from django.http import JsonResponse
from django.views.decorators.http import require_POST

SECRET_KEY = 'your-secret-key'  # In settings, use settings.SECRET_KEY

def create_signed_token(data):
    payload = {
        'data': data,
        'nonce': str(uuid.uuid4()),  # unique per request
        'iat': int(time.time()),
    }
    signed = signing.dumps(payload, key=SECRET_KEY)
    return signed

@require_POST
def process_payment(request):
    signed_token = request.POST.get('token')
    if not signed_token:
        return JsonResponse({'error': 'missing token'}, status=400)
    try:
        payload = signing.loads(signed_token, key=SECRET_KEY, max_age=300)
    except signing.BadSignature:
        return JsonResponse({'error': 'invalid signature'}, status=400)

    # Idempotency check: store processed nonce in cache/database
    from django.core.cache import cache
    if cache.get(f"processed_nonce:{payload['nonce']}"):
        return JsonResponse({'error': 'duplicate request'}, status=409)

    # Process payment safely
    amount = payload['data'].get('amount')
    user_id = payload['data'].get('user_id')
    # ... perform payment logic ...

    # Mark nonce as processed
    cache.set(f"processed_nonce:{payload['nonce']}", True, timeout=86400)
    return JsonResponse({'status': 'ok'})

Example 2: HMAC verification with replay protection using a database model

import hmac
import hashlib
import time
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from .models import ProcessedRequest

def verify_hmac_signature(data, signature, secret):
    computed = hmac.new(
        secret.encode(),
        msg=data.encode(),
        digestmod=hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(computed, signature)

@require_POST
def handle_webhook(request):
    body = request.body.decode('utf-8')
    signature = request.META.get('HTTP_X_SIGNATURE')
    secret = 'webhook-secret'

    if not verify_hmac_signature(body, signature, secret):
        return JsonResponse({'error': 'invalid signature'}, status=400)

    # Prevent replay: store request hash with timestamp
    import hashlib
    request_hash = hashlib.sha256(body.encode()).hexdigest()
    if ProcessedRequest.objects.filter(request_hash=request_hash).exists():
        return JsonResponse({'error': 'duplicate webhook'}, status=409)

    # Process webhook data
    # ...

    ProcessedRequest.objects.create(request_hash=request_hash, received_at=int(time.time()))
    return JsonResponse({'status': 'processed'})

Best practices summary

  • Include a unique nonce or idempotency key within the signed payload and enforce one-time use.
  • Use hmac.compare_digest to avoid timing attacks during signature verification.
  • Store processed nonces or request hashes with an appropriate TTL to bound storage growth.
  • Combine HMAC validation with rate limiting and transaction-level deduplication for defense in depth.

Frequently Asked Questions

How does middleBrick help detect Double Free risks with Hmac Signatures?
middleBrick scans unauthenticated attack surfaces and maps findings to frameworks like OWASP API Top 10. For Hmac Signatures in Django, it checks for missing idempotency controls and replay protections, reporting Double Free risks with severity, evidence, and remediation guidance.
Can middleBrick test LLM endpoints used in Django applications for related security issues?
Yes. middleBrick uniquely probes unauthenticated LLM endpoints for prompt injection, jailbreaks, and output leakage, and it checks for excessive agency patterns that could affect Django-based AI integrations.