Crlf Injection in Fastapi with Basic Auth
Crlf Injection in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when user-controlled data is reflected in HTTP headers without proper sanitization, allowing an attacker to inject carriage return (CR, \r) and line feed (\n) sequences. In Fastapi, combining Crlf Injection with Basic Auth can expose both authentication-related header handling and downstream request routing risks.
When a Fastapi application uses Basic Auth, the Authorization header is typically parsed to extract the base64-encoded credentials. If the application or an underlying library then reflects any user input — such as a username, transaction ID, or custom header — into other response headers, an attacker can supply \r\n sequences to split the header chain. This can lead to response splitting, header injection, or cache poisoning. For example, an attacker might set a username like admin\r\nX-Admin: true; if the server places the username into a response header without validation, the injected header may be interpreted as a new header by some clients or intermediaries.
Even though Basic Auth credentials are base64-encoded and typically not directly reflected, the username portion may be logged, echoed in error messages, or used to construct downstream URLs and headers. If user input derived from the authentication context (such as a parsed username) is concatenated into headers like Location or custom headers, Crlf Injection becomes feasible. This becomes especially relevant when Fastapi routes use the authenticated identity to build redirects or to call other services, where untrusted data reaches header construction logic.
Moreover, if the application uses OpenAPI/Swagger specs with $ref resolutions that describe header schemas, runtime findings from unchecked user input may expose mismatches between documented and actual header handling. The 12 parallel security checks in middleBrick include Input Validation and Property Authorization, which can surface these inconsistencies across spec definitions and runtime behavior when authentication headers are involved.
Basic Auth-Specific Remediation in Fastapi — concrete code fixes
To mitigate Crlf Injection in Fastapi while using Basic Auth, ensure strict validation and encoding of any data that may reach HTTP headers, and avoid reflecting untrusted input in headers altogether. Below are concrete remediation steps and code examples.
- Validate and sanitize any user-controlled strings before using them in header construction. Reject or encode CR and LF characters explicitly.
- Do not directly interpolate user input into response headers such as
Location,WWW-Authenticate, or custom headers. - Use Fastapi’s dependency injection for authentication and keep header construction confined to trusted, server-side values.
Example: Secure Basic Auth parsing and header-safe usage
from fastapi import Fastapi, Depends, Header, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import base64
import re
app = Fastapi()
security = HTTPBasic()
# Strict validation: allow only safe characters in username/password
SAFE_USERNAME_RE = re.compile(r'^[a-zA-Z0-9_.-]+$')
def verify_credentials(credentials: HTTPBasicCredentials = Depends(security)):
if not credentials.username or not credentials.password:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing credentials"
)
# Reject usernames containing characters that could enable header injection
if not SAFE_USERNAME_RE.match(credentials.username):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid username format"
)
# Perform your actual verification (e.g., check hashed password)
if credentials.username != "admin" or credentials.password != "correcthorsebatterystaple":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect credentials"
)
return credentials.username
@app.get("/secure-endpoint")
def secure_route(x_custom: str = Header(None)):
# Example: do not reflect user-supplied header values directly
if x_custom and ("\n" in x_custom or "\r" in x_custom):
raise HTTPException(status_code=400, detail="Header contains disallowed characters")
return {"message": "safe", "header_echo": x_custom}
@app.get("/auth-parse")
def parse_auth(credentials: HTTPBasicCredentials = Depends(security)):
username = verify_credentials(credentials)
# Use username only in safe, non-header contexts (e.g., response body)
return {"username": username, "note": "Do not reflect username in headers"}
Additional recommendations: configure middleware to strip or reject \r and \n from incoming header values, and enforce strict content security policies for any redirects. When integrating with other tools, leverage middleBrick’s parallel checks — such as Input Validation and Property Authorization — to continuously verify that header handling remains consistent with your OpenAPI/Swagger spec definitions and runtime behavior.