Crlf Injection with Api Keys
How Crlf Injection Manifests in Api Keys
CRLF injection in API keys typically occurs when untrusted user input containing carriage return (\r) and line feed (\n) characters is processed without proper sanitization. In API key contexts, this vulnerability can manifest in several critical ways:
# Vulnerable API key generation endpoint
@app.route('/api/keys', methods=['POST'])
def generate_key():
user_input = request.json.get('description', '')
key = generate_api_key()
# CRLF injection point - user_input goes directly into response headers
response = make_response({'key': key})
response.headers['X-Key-Description'] = user_input
return responseAn attacker could submit a description like valid description\r\nSet-Cookie: sessionid=malicious, which would inject additional HTTP headers into the response, potentially hijacking user sessions or manipulating browser behavior.
// Vulnerable API key storage with CRLF in metadata
const storeKey = async (keyData) => {
const { key, metadata } = keyData;
// If metadata contains CRLF, it can break CSV/JSON storage formats
const csvLine = `${key},${metadata}\n`;
await fs.appendFile('keys.csv', csvLine);
};
// Attack: metadata = "[email protected]\r\[email protected],admin,true"Another common manifestation occurs in API key validation logs where CRLF characters in key descriptions or metadata can corrupt log files, enabling log injection attacks that bypass security monitoring.
// Vulnerable API key validation endpoint
@PostMapping("/validate")
public ResponseEntity<String> validateKey(@RequestBody KeyValidationRequest request) {
String key = request.getKey();
String userAgent = request.getUserAgent();
// CRLF in userAgent can manipulate HTTP response splitting
if (isKeyValid(key)) {
return ResponseEntity
.ok()
.header("X-Validated-By", userAgent) // Vulnerable line
.body("Key validated successfully");
}
return ResponseEntity.badRequest().body("Invalid key");
}Api Keys-Specific Detection
Detecting CRLF injection in API key systems requires both static analysis and dynamic testing. Here are the most effective detection approaches:
# Using middleBrick CLI to scan for CRLF injection vulnerabilities
middlebrick scan https://api.example.com/keys \
--test-headers \
--test-log-injection \
--test-response-splitting
# Output will show:
# - Headers vulnerable to CRLF injection
# - Log files susceptible to injection
# - Response splitting opportunities
# - Severity scores per categorymiddleBrick's black-box scanning specifically tests for CRLF injection by sending payloads with various CRLF combinations and monitoring for abnormal responses, header manipulation, or log corruption.
# Automated detection script for API key endpoints
def detect_crlf_vulnerabilities(app):
test_cases = [
'normal\r\nInjected: header',
'test\r\nContent-Type: application/json',
'payload\r\nLocation: https://evil.com'
]
vulnerabilities = []
for case in test_cases:
response = test_api_key_endpoint(case)
if has_injected_headers(response):
vulnerabilities.append({
'input': case,
'response': response,
'severity': 'high'
})
return vulnerabilities
# middleBrick performs similar automated testing across 12 security categoriesStatic code analysis tools should flag any string concatenation that includes user input in header construction, log writing, or response building. Look for patterns like:
# Dangerous patterns to flag
response.headers[header_name] = user_input # Potential CRLF injection
log_message = f"{user_input}: {event}" # Potential log injection
csv_line = f"{key},{metadata}\n" # Potential CSV injectionApi Keys-Specific Remediation
Remediating CRLF injection in API key systems requires input validation, output encoding, and secure coding practices. Here are specific fixes for API key contexts:
# Secure API key generation with CRLF sanitization
import re
from flask import Flask, request, make_response
app = Flask(__name__)
def sanitize_crlf(input_str):
"""Remove or encode CRLF characters"""
if not isinstance(input_str, str):
return input_str
# Remove CRLF characters
sanitized = re.sub(r'[
]+', '', input_str)
# Alternative: URL encode dangerous characters
# sanitized = input_str.replace('\r', '%0D').replace('\n', '%0A')
return sanitized
@app.route('/api/keys', methods=['POST'])
def generate_key():
user_input = request.json.get('description', '')
sanitized_input = sanitize_crlf(user_input)
key = generate_api_key()
response = make_response({'key': key})
# Safe header setting - input is sanitized
response.headers['X-Key-Description'] = sanitized_input
return responseFor API key storage and logging, use structured formats that inherently resist CRLF injection:
// Secure API key storage using JSON instead of CSV
const storeKeySecurely = async (keyData) => {
const { key, metadata } = keyData;
const record = { key, metadata, timestamp: new Date().toISOString() };
// JSON storage - no CRLF injection possible
await fs.appendFile('keys.json', JSON.stringify(record) + '\n');
};
// Secure logging with structured format
const logKeyEvent = async (key, event, metadata) => {
const logEntry = {
timestamp: new Date().toISOString(),
key_id: key.id,
event: event,
metadata: metadata
};
// Structured logging prevents injection
await logger.info(JSON.stringify(logEntry));
};When building HTTP responses with user-controlled data, use framework-safe methods:
// Secure API key validation with proper header handling
@PostMapping("/validate")
public ResponseEntity<String> validateKey(@RequestBody KeyValidationRequest request) {
String key = request.getKey();
String userAgent = request.getUserAgent();
// Sanitize userAgent before using in headers
String safeUserAgent = userAgent.replaceAll("[
]", "");
if (isKeyValid(key)) {
return ResponseEntity
.ok()
.header("X-Validated-By", safeUserAgent)
.body("Key validated successfully");
}
return ResponseEntity.badRequest().body("Invalid key");
}middleBrick's scanning can verify these remediations by testing with various CRLF payloads and confirming no injection occurs.