Crlf Injection in Fastapi (Python)
Crlf Injection in Fastapi with Python
Crlf Injection occurs when an attacker can inject a carriage return (CR, \r) and line feed (\n) sequence into a header or status line, causing the header to be split and additional headers or response content to be injected. In Fastapi with Python, this typically arises when user-controlled input is placed into HTTP headers, the status code path, or constructed into raw WSGI/ASGI responses without proper sanitization. Fastapi relies on Starlette for the ASGI layer, and Starlette passes through header values as provided by the application. If the application directly uses request query parameters, body fields, or path segments to build header values or status codes, an attacker can supply \r\n to create a new line, appending arbitrary headers such as Set-Cookie or Content-Type, or even injecting a response body.
For example, consider an endpoint that echoes a client-supplied label into a custom header. Without validation, a payload like label=OK%0D%0AX-Injected:%20malicious (where %0D%0A decodes to \r\n) results in two headers: one labeled Label with value OK and another labeled X-Injected with value malicious. Because Python string handling preserves these characters, the ASGI server sends the split lines as separate headers, which many clients process as intended by the attacker. In more complex scenarios, an attacker can inject a second status line or additional CRLF-separated content, leading to response splitting or cache poisoning. The risk is elevated when the application constructs headers using f-strings or concatenation like f'prefix {user_value}' without removing or encoding CR and LF characters. Input validation must explicitly disallow or neutralize \r and \n in any data that influences headers or status codes.
Another common pattern involves redirect URLs. If Fastapi builds a redirect location using user input, an injected CRLF can append new headers or content before the redirect, causing clients to follow a malicious location or interpret injected content as a separate response. Because Fastapi applications often integrate with frameworks that expose low-level response objects, developers must ensure that any user-controlled string used in headers, status codes, or redirect targets is sanitized. Tools like middleBrick can detect endpoints where unsanitized input reaches header construction logic by analyzing the OpenAPI spec and runtime behavior, highlighting risky patterns such as direct header assignment or missing normalization of line-ending characters.
Python-Specific Remediation in Fastapi
Remediation focuses on disallowing CR and LF characters in any user-controlled data used for headers, status codes, or redirect targets. The simplest and safest approach is to reject or strip these characters early in request processing. Below are concrete Fastapi examples showing vulnerable and fixed patterns.
Vulnerable header assignment:
from fastapi import FastAPI, Request
app = FastAPI()
@app.get("/vulnerable")
async def vulnerable(label: str):
# UNSAFE: user input directly used in a header
return {"label": label}
An attacker can supply label=OK\r\nX-Injected:malicious and the server may expose the injected header depending on how the response is serialized by the ASGI server. Although Fastapi does not automatically add this header, if the application uses a response model or manually sets headers, the risk becomes real.
Safe header assignment with validation:
from fastapi import FastAPI, Header, HTTPException
import re
app = FastAPI()
CRLF_RE = re.compile(r'[\r\n]')
def safe_header(value: str) -> str:
if CRLF_RE.search(value):
raise HTTPException(status_code=400, detail="Invalid header value")
return value
@app.get("/safe")
async def safe(label: str = Header(...)):
clean_label = safe_header(label)
# Use clean_label in business logic; do not inject into raw response headers
return {"label": clean_label}
This pattern validates the input and raises a 400 error if CR or LF is detected. For redirects, validate the target URL and ensure it does not contain line-ending characters before passing it to Redirect or Response. Never attempt to escape CRLF by encoding; the safest action is to reject the input.
Using Response with explicit headers:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/headers")
async def set_custom_header():
response = JSONResponse(content={"status": "ok"})
# Explicit, static header values are safe
response.headers['X-Content-Type-Options'] = 'nosniff'
return response
When headers must be dynamic, ensure the source is constrained (e.g., enumerated choices) and validated against CRLF. For user-supplied redirect targets, use a whitelist of allowed hosts and avoid concatenating raw strings into the location header.
middleBrick can complement these defenses by scanning the API definition and runtime behavior to identify endpoints where user input reaches headers or status-related constructs. Its checks include tracing data flows from inputs to outputs, helping teams find missing validation in Python Fastapi services before attackers can exploit CRLF Injection.