Log Injection in Fastapi with Hmac Signatures
Log Injection in Fastapi with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Log injection occurs when untrusted data is written into application logs without proper sanitization, enabling log forging or log injection attacks that can obscure attacker activity or trigger log-based security controls. In FastAPI applications that use HMAC signatures for request integrity and authentication, log injection can emerge from two dimensions: the application logging data derived from signed payloads, and the way signature verification logic is recorded.
Consider a FastAPI endpoint that validates an HMAC signature included in a request header and then logs details from the authenticated payload. If the payload includes user-controlled fields such as username, action, or resource, and these values are written directly into logs without sanitization, an attacker can inject newline characters or structured log delimiters to forge log entries. For example, a crafted payload can produce log lines that appear to originate from a different user or that inject fake events into audit trails.
HMAC signatures themselves do not prevent log injection; they ensure integrity and authenticity of the signed content. If the application logs the signature value or parts of the signed message without care, it may inadvertently expose sensitive data or structured tokens in logs. Moreover, if verification failures are logged with detailed exception messages or stack traces, attackers can probe differences in log output to infer whether a signature was valid, aiding tampering or side-channel analysis.
In FastAPI, a common pattern decodes and verifies an HMAC before processing business logic. If the verification logic logs the decoded payload or the signature verbatim, and the payload includes unescaped user input, the log line can be manipulated. For instance, an attacker can embed carriage returns or control characters in a string field, causing the log entry to span multiple lines and potentially bypass log parsers or SIEM rules that rely on line-based ingestion.
Real-world impacts include log forging to hide malicious actions, injection of misleading entries that trigger automated alerts, and exposure of sensitive identifiers through verbose logging. While HMAC ensures that a tampered payload is rejected, insecure logging of verified data still weakens auditability. Mitigations focus on strict input validation for log-worthy fields, structured and sanitized log formats, and avoiding logging raw signatures or sensitive payload components.
Hmac Signatures-Specific Remediation in Fastapi — concrete code fixes
To mitigate log injection when using HMAC signatures in FastAPI, ensure that all data written to logs is sanitized, and that logging does not expose raw signatures or sensitive payload content. Below are concrete, working examples that demonstrate secure handling.
First, use a utility to sanitize strings before logging, escaping newlines and control characters:
import re
def sanitize_for_log(value: str) -> str:
# Replace newlines and control characters to prevent log injection
return re.sub(r'[\r\n\x00-\x1f\x7f]', '?', value)
Second, structure your HMAC verification and logging so that only safe, normalized data is recorded:
from fastapi import FastAPI, Header, HTTPException
import hmac
import hashlib
import logging
logger = logging.getLogger(__name__)
app = FastAPI()
SECRET = b'super-secret-key'
def verify_hmac(payload: bytes, signature: str) -> bool:
computed = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, signature)
@app.post('/action')
async def perform_action(payload: str, signature: str = Header(...)):
if not verify_hmac(payload.encode('utf-8'), signature):
logger.warning('Signature verification failed for sanitized payload: %s', sanitize_for_log(payload[:100]))
raise HTTPException(status_code=401, detail='Invalid signature')
# Safe logging: sanitize user input and avoid logging raw signature
safe_payload = sanitize_for_log(payload)
logger.info('Action processed for payload: %s', safe_payload)
return {'status': 'ok'}
Third, if you log structured events, use key-value formats that are less susceptible to injection, and ensure newline characters are escaped or replaced:
import json
def safe_log_event(event_type: str, details: dict):
sanitized = {k: sanitize_for_log(str(v)) for k, v in details.items()}
logger.info(json.dumps({'event': event_type, 'details': sanitized}))
# Usage
safe_log_event('action', {'user': payload.get('user'), 'resource': payload.get('resource')})
These practices ensure that HMAC-based authentication does not inadvertently amplify log injection risks. By sanitizing inputs before they reach log statements and avoiding verbose logging of raw signatures, you maintain both integrity verification and clean, reliable audit trails.