MEDIUM log injectionfastapi

Log Injection in Fastapi

How Log Injection Manifests in Fastapi

Log injection in Fastapi occurs when untrusted user input flows directly into log statements without proper sanitization. Fastapi's async nature and dependency injection system create unique injection points that developers often overlook.

The most common Fastapi-specific vector involves dependency injection parameters. Consider this vulnerable pattern:

from fastapi import FastAPI, Depends

app = FastAPI()

async def get_user_agent(headers: dict = Depends()) -> str:
    return headers.get('user-agent', 'unknown')

@app.get('/api/data')
async def read_data(user_agent: str = Depends(get_user_agent)):
    logger.info(f'User agent: {user_agent}')
    return {'data': 'sensitive info'}

An attacker can craft a User-Agent header containing newline characters and log levels:

User-Agent: 
INFO - User agent: normal
ERROR - Critical error occurred

This injects a fake INFO log followed by an ERROR log, polluting the log stream and potentially triggering false alerts.

Fastapi's exception handlers create another injection point. When exceptions occur, Fastapi automatically logs the request body and headers:

@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    logger.error(f'ValueError: {exc}')
    return JSONResponse(
        status_code=400,
        content={"message": str(exc)}
    )

If the exception message contains user input with newline characters, it breaks the log structure. Fastapi's automatic request logging also captures the full request body, which could contain malicious log injection payloads.

Background tasks in Fastapi introduce timing-based injection risks. When user input flows into background tasks that log asynchronously:

@app.post('/upload')
async def upload_file(file: UploadFile = File(...)):
    contents = await file.read()
    
    async def process_and_log():
        logger.info(f'Processing file: {contents.decode()}')
    
    await asyncio.create_task(process_and_log())
    return {'status': 'uploaded'}

The async logging can interleave with other log entries, making injection payloads harder to detect and correlate with the original request.

Fastapi-Specific Detection

Detecting log injection in Fastapi requires examining both the application code and runtime behavior. Static analysis should focus on these Fastapi-specific patterns:

First, scan for direct string interpolation in log statements where user input flows through dependency injection or request parameters. middleBrick's Fastapi scanner automatically detects these patterns by analyzing the dependency injection graph and identifying parameters that could contain untrusted data.

middleBrick tests for log injection by sending payloads containing newline characters and log levels through all request parameters, headers, and body fields. The scanner monitors the application's log output (if accessible) or looks for indicators like:

  • Unexpected log levels in the response headers
  • Time-based discrepancies suggesting async log injection
  • Corrupted log structure in any accessible log endpoints

For Fastapi applications using structured logging (like structlog or Loguru), middleBrick analyzes the logging configuration to identify vulnerable format strings. The scanner specifically checks for Fastapi's built-in logging behavior, including:

# Fastapi's default access log - vulnerable if user input flows here
# Example: INFO:     127.0.0.1:54321 - "GET /api/data HTTP/1.1" status: 200

middleBrick's LLM security module adds another layer of detection for Fastapi applications that serve AI endpoints. It tests for prompt injection that could manipulate logging behavior in LLM responses, a unique Fastapi vulnerability when using async AI libraries.

Runtime detection should monitor for:

  • Log entries with unexpected timestamps or source IPs
  • Log levels appearing in user-controlled fields
  • Structured log corruption (missing fields, extra levels)

The middleBrick CLI tool can scan a running Fastapi instance with: middlebrick scan https://your-fastapi-app.com, providing a security score and specific findings about log injection vulnerabilities.

Fastapi-Specific Remediation

Remediating log injection in Fastapi requires both input sanitization and architectural changes. The most effective approach combines Fastapi's type system with explicit sanitization.

For dependency injection parameters, use Pydantic models with custom validators:

from pydantic import BaseModel, validator
import re

class SafeUserAgent(BaseModel):
    user_agent: str
    
    @validator('user_agent')
    def sanitize_user_agent(cls, v):
        # Remove newlines and carriage returns
        v = re.sub(r'[\n\r]', ' ', v)
        # Remove ANSI color codes
        v = re.sub(r'\x1B\[[0-9;]*[mK]', '', v)
        return v

async def get_safe_user_agent(headers: dict = Depends()) -> str:
    return SafeUserAgent(**headers).user_agent

For request body validation, Fastapi's Pydantic integration provides automatic sanitization:

from typing import Dict
from pydantic import BaseModel

class LogSafeData(BaseModel):
    message: str
    
    @validator('message')
    def sanitize_message(cls, v):
        return re.sub(r'[\n\r]', ' ', v)

@app.post('/api/log')
async def log_message(data: LogSafeData):
    logger.info(f'Message: {data.message}')
    return {'status': 'logged'}

Fastapi's exception handlers should sanitize exception messages before logging:

@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    sanitized_msg = re.sub(r'[\n\r]', ' ', str(exc))
    logger.error(f'ValueError: {sanitized_msg}')
    return JSONResponse(
        status_code=400,
        content={"message": sanitized_msg}
    )

For background tasks, use Fastapi's built-in task system with proper context passing:

from fastapi import BackgroundTasks

@app.post('/upload')
async def upload_file(
    file: UploadFile = File(...),
    background_tasks: BackgroundTasks = Depends()
):
    contents = await file.read()
    
    def process_and_log():
        sanitized = re.sub(r'[\n\r]', ' ', contents.decode())
        logger.info(f'Processing file: {sanitized}')
    
    background_tasks.add_task(process_and_log)
    return {'status': 'uploaded'}

Implement structured logging with Fastapi middleware to ensure consistent log formatting:

from fastapi.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
import structlog

class LogSanitizingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        response = await call_next(request)
        
        # Sanitize any user data before it reaches structured logging
        if 'user-agent' in request.headers:
            ua = request.headers['user-agent']
            sanitized_ua = re.sub(r'[\n\r]', ' ', ua)
            request.headers['user-agent'] = sanitized_ua
        
        return response

Finally, configure Fastapi's logging to use structured formatters that escape special characters:

import logging
import structlog

structlog.configure(
    processors=[
        structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
    ],
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    wrapper_class=structlog.stdlib.BoundLogger,
    cache_logger_on_first_use=True,
)

formatter = structlog.stdlib.ProcessorFormatter(
    processor=structlog.dev.ConsoleRenderer(),
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)

logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)

Frequently Asked Questions

How does Fastapi's async nature make log injection harder to detect?
Fastapi's async background tasks can log user input at unpredictable times, causing log injection payloads to interleave with unrelated log entries. This makes correlation difficult and allows attackers to hide malicious logs among legitimate entries. middleBrick's scanner tests for async injection by monitoring log timing and structure across concurrent requests.
Can log injection in Fastapi lead to other security issues?
Yes, log injection can trigger false security alerts, obscure real attacks in log monitoring systems, and even cause log parsing failures that crash log aggregation services. In Fastapi applications using structured logging for audit trails, injection can corrupt compliance records. middleBrick's scanner checks for these cascading effects by testing how injected logs affect downstream processing.