Log Injection in Django with Hmac Signatures
Log Injection in Django with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Log injection occurs when an attacker can control or influence data that is written to application logs. In Django, this often happens through log messages that include unchecked user input, such as request parameters, headers, or cookies. When HMAC signatures are generated and then logged without validation or sanitization, the signature value itself can become a vector if it is derived from or includes untrusted data.
Consider a scenario where a Django view builds an HMAC signature using a combination of a shared secret and a message that includes a user-controlled field (e.g., a transaction ID or a query parameter). If the resulting signature is logged verbatim—perhaps for debugging or audit purposes—an attacker can supply input that introduces newline characters or other control sequences into the logged message. This can lead to log forging, where additional lines that look like legitimate log entries are injected into the log file. These forged lines may mimic structured log formats, potentially evading simple log parsers or obscuring other malicious activity.
Another subtle risk involves logging the signature alongside metadata that includes unescaped user input. For example, if a log line combines a timestamp, a user identifier, and the HMAC signature without proper sanitization, an attacker can supply newlines or delimiters in the user identifier to split the log line into multiple entries. This can break log integrity assumptions, making it harder to correlate events or detect tampering. Because HMAC signatures are often long hexadecimal strings, they may also be mistakenly treated as safe, leading developers to skip input validation on the data used to construct them.
Django’s default logging configuration does not inherently sanitize message arguments, so it is the developer’s responsibility to ensure that any data included in log records is safe. When HMAC signatures are generated from user-influenced inputs, the resulting log entries should treat both the signature and its constituent parts as untrusted. Failing to do so can expose the application to log injection, which may be leveraged in tandem with other weaknesses, such as insecure log access or insufficient monitoring, to diminish the effectiveness of security analysis.
Hmac Signatures-Specific Remediation in Django — concrete code fixes
To mitigate log injection when working with HMAC signatures in Django, ensure that any data used to compute or accompany the signature is sanitized before being written to logs. Do not log raw user input directly; instead, escape or remove control characters such as newlines and carriage returns. When constructing log messages, use structured logging with explicit field separation rather than string concatenation that can be influenced by attacker input.
Below is an example of a Django view that safely handles HMAC signatures while avoiding log injection. The code computes an HMAC over a message that excludes untrusted data, and it logs only sanitized, predefined fields.
import hmac
import hashlib
import logging
import re
from django.http import JsonResponse
from django.views import View
logger = logging.getLogger(__name__)
def sanitize_log_text(text: str) -> str:
# Remove newlines and other control characters that can fragment logs
return re.sub(r'[\r\n\x00-\x1f\x7f]', '', text)
class PaymentView(View):
def post(self, request):
transaction_id = request.POST.get('transaction_id', '')
amount = request.POST.get('amount', '')
# Do NOT include user input directly in the HMAC message
secret = b'super-secret-shared-key'
message = f'transaction_id:{transaction_id};amount:{amount}'
signature = hmac.new(secret, msg=message.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
# Sanitize any user data before logging
safe_transaction_id = sanitize_log_text(transaction_id)
safe_amount = sanitize_log_text(amount)
safe_signature = sanitize_log_text(signature)
logger.info(
'Processed payment',
extra={
'transaction_id': safe_transaction_id,
'amount': safe_amount,
'signature': safe_signature,
}
)
return JsonResponse({'status': 'ok', 'signature': signature})
In this example, the HMAC signature is computed over a message that explicitly includes only safe, internal data. User input is excluded from the signature computation to avoid conflating business logic with integrity checks. Before logging, each potentially sensitive field is passed through sanitize_log_text, which removes characters commonly used for log injection. The logger uses structured keyword arguments via extra rather than embedding values directly into the message string, which reduces the risk of delimiter confusion.
Additionally, prefer using Django’s built-in logging configuration to enforce safe formatting. Avoid constructing log messages by interpolating raw signature strings into URLs or error messages that might later be surfaced to users. If you use the CLI (middlebrick scan <url>), the GitHub Action, or the MCP Server to integrate scans into your CI/CD pipeline, ensure that log-related findings are reviewed as part of your security gates.