Type Confusion in Django with Hmac Signatures
Type Confusion in Django with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Type confusion in the context of Django HMAC signatures arises when a value expected to be of one type (e.g., an integer or a UUID) is instead interpreted as another type (e.g., a string) during signature generation or verification. This can lead to a security bypass because the HMAC computation depends on exact input formatting and type-sensitive serialization. In Django, HMAC is commonly used in signing utilities such as django.core.signing and in CSRF/token generation where data integrity and origin authenticity are critical.
Consider a scenario where an API endpoint accepts an identifier parameter that should be an integer but is later concatenated with a secret key as a string to compute an HMAC. If an attacker supplies a crafted string that, when interpreted as an integer, yields a different serialized form (e.g., 0 vs. "0"), the signature verification may incorrectly validate due to type mismatch. This is a type confusion issue: the signer and verifier do not enforce strict type constraints, allowing an attacker to manipulate how data is interpreted without changing the cryptographic material in a detectable way.
In Django, HMAC signatures are often generated using django.core.signing.dumps and verified with django.core.signing.loads. If the data structure includes polymorphic fields or if the serializer does not enforce strict typing (for example, JSON deserialization may convert numeric strings into integers), the resulting signature can be valid across multiple type interpretations. An attacker can exploit this by submitting a value that triggers a different internal type path, bypassing expected validation logic. For instance, a token that should represent a user ID as an integer might be accepted as a string, leading to privilege escalation or unauthorized access when the application logic branches on type-sensitive checks.
Real-world attack patterns related to this issue can intersect with other API security checks that middleBrick scans for, such as Input Validation and BOLA/IDOR. If an endpoint uses HMAC to authorize access to a resource but suffers from type confusion, an unauthenticated scan may reveal that the signature verification is too permissive, potentially allowing an attacker to manipulate identifiers or parameters without invalidating the cryptographic integrity of the request.
To detect such issues, security scans should examine how HMAC-signed payloads are constructed and validated, ensuring that type constraints are enforced before signing and after verification. MiddleBrick’s checks for Input Validation and Property Authorization can help surface cases where type confusion intersects with weak authorization logic, providing actionable findings with severity ratings and remediation guidance.
Hmac Signatures-Specific Remediation in Django — concrete code fixes
Remediation focuses on enforcing strict type handling and canonical serialization before computing or verifying HMAC signatures. Always normalize inputs to a consistent type and use explicit serialization formats that preserve type information. In Django, prefer using structured serialization such as JSON with typed fields, and validate types before incorporating data into HMAC computations.
Example of vulnerable code that concatenates user input directly into an HMAC without type enforcement:
import hashlib
import hmac
from django.conf import settings
def generate_vulnerable_signature(user_id):
# WARNING: user_id may be coerced between int and str, leading to type confusion
message = str(user_id) + settings.SECRET_KEY
return hmac.new(key=settings.SECRET_KEY.encode(), msg=message.encode(), digestmod=hashlib.sha256).hexdigest()
def verify_vulnerable_signature(user_id, signature):
expected = generate_vulnerable_signature(user_id)
return hmac.compare_digest(expected, signature)
The above example is vulnerable because user_id is cast to str only at signing time, but an attacker might supply numeric strings or integers that produce different string representations. A safer approach is to enforce a canonical type and serialization format:
import hashlib
import hmac
import json
from django.conf import settings
def generate_safe_signature(data):
# Enforce strict typing: data must be a dict with known, typed fields
if not isinstance(data.get('user_id'), int):
raise ValueError('user_id must be an integer')
# Canonical JSON serialization with sorted keys to ensure deterministic output
canonical = json.dumps(data, sort_keys=True, separators=(',', ':'))
return hmac.new(key=settings.SECRET_KEY.encode(), msg=canonical.encode(), digestmod=hashlib.sha256).hexdigest()
def verify_safe_signature(data, signature):
if not isinstance(data.get('user_id'), int):
raise ValueError('user_id must be an integer')
expected = generate_safe_signature(data)
return hmac.compare_digest(expected, signature)
# Usage example:
payload = {'user_id': 42, 'action': 'access_resource'}
sig = generate_safe_signature(payload)
assert verify_safe_signature(payload, sig)
When using Django’s signing utilities, ensure that the data passed to dumps is consistently typed and that loads validates types on deserialization:
from django.core import signing
import json
def sign_typed_data(data):
# Ensure data is JSON-serializable with strict types
if not isinstance(data.get('user_id'), int):
raise ValueError('user_id must be an integer')
return signing.dumps(data)
def unsign_typed_data(token):
data = signing.loads(token)
if not isinstance(data.get('user_id'), int):
raise ValueError('Invalid type for user_id after deserialization')
return data
These practices reduce the risk of type confusion by enforcing type checks before and after cryptographic operations. They align with secure coding guidance for input validation and help ensure that HMAC-based authorization remains robust against manipulation of data representation.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |