CWE-93 in APIs
- CWE ID
- CWE-93
- Category
- Input Validation
- Severity
- MEDIUM
- Short Name
- CRLF Injection
What is CWE-93?
CWE-93 refers to Improper Neutralization of CRLF Sequences ('CRLF Injection'). This weakness occurs when an application fails to neutralize carriage return and line feed characters in user-controlled data. Attackers can inject malicious CRLF sequences to manipulate the structure of data, often leading to HTTP response splitting, log injection, or header injection attacks.
The vulnerability arises because CRLF sequences ( ) are control characters that signify the end of a line in many protocols. When user input containing these sequences is not properly sanitized before being included in HTTP headers, logs, or other structured data, an attacker can insert additional headers, split responses, or inject arbitrary content.
CWE-93 in API Contexts
In API development, CWE-93 commonly manifests in several ways:
- HTTP Header Injection: APIs that reflect user input in headers without sanitization can be manipulated to add new headers or split responses
- Log Injection: APIs that log user input without proper escaping can have their logs manipulated, potentially hiding malicious activity or injecting false entries
- CSV Injection: APIs generating CSV files that include user input without sanitization can be exploited for formula injection
- WebSocket Messages: APIs using WebSockets that don't properly handle message framing can be vulnerable to message injection
Consider an API endpoint that logs user agent strings:
const logUserAgent = (req, res) => {
const userAgent = req.headers['user-agent'];
console.log(`User agent: ${userAgent}`);
res.json({ message: 'Logged' });
};
If an attacker sends a user agent containing sequences, they can inject arbitrary log entries, potentially obscuring their actual activity.
Detection
Detecting CWE-93 requires both manual code review and automated scanning. Look for these patterns:
- Direct inclusion of user input in HTTP headers without validation
- Concatenation of user input into log messages
- Reflection of user input in response headers
- Generation of CSV or other structured files with unvalidated user input
middleBrick scans for CRLF injection vulnerabilities by testing API endpoints with specially crafted payloads containing sequences. The scanner attempts to inject CRLF sequences into parameters, headers, and request bodies to observe if the API is vulnerable to response splitting or header injection.
For example, middleBrick might test with payloads like:
name=Bob%0D%0ALocation:%20http://evil.com
Content-Type:%20text/html
%0D%0AHTTP/1.1%20200%20OK
%0D%0AContent-Type:%20text/html
%0D%0A
%0D%0A<script>alert('XSS')</script>
If the API reflects this payload in headers or responses without proper neutralization, it indicates a vulnerability.
middleBrick's black-box scanning approach tests the actual runtime behavior of your API without requiring source code access, making it effective for identifying CRLF injection in production environments.
Remediation
Fixing CWE-93 requires proper input validation and output encoding. Here are effective remediation strategies:
1. Input Validation
Validate and sanitize all user input before processing. Remove or encode CRLF sequences:
function sanitizeInput(input) {
if (typeof input !== 'string') return input;
return input.replace(/[
]+/g, '');
}
// Usage
const safeInput = sanitizeInput(req.query.name);
2. HTTP Header Construction
When constructing HTTP headers, use safe APIs that automatically handle encoding:
// Bad - vulnerable to injection
res.setHeader('X-User', userInput);
// Good - use safe methods
res.setHeader('X-User', encodeURIComponent(userInput));
3. Log Sanitization
Sanitize log entries to prevent injection:
function safeLog(message, data) {
const sanitizedData = data.replace(/[
]/g, ' ');
console.log(`${message}: ${sanitizedData}`);
}
4. CSV Generation
When generating CSV files, properly escape user input:
function escapeCSV(input) {
if (input.includes(',') || input.includes('
') || input.includes('
') || input.includes('"')) {
return '"' + input.replace(/"/g, '""') + '"';
}
return input;
}
// Usage
const csvRow = [escapeCSV(name), escapeCSV(email), escapeCSV(message)].join(',');
5. Framework-Specific Protections
Leverage framework protections when available:
// Express.js - use built-in escaping
app.set('json escape', true);
// FastAPI - use Pydantic models with validation
from fastapi import FastAPI
from pydantic import BaseModel
class SafeInput(BaseModel):
name: str = Field(..., regex=r'^[^
]*$')
The key principle is to never trust user input and always validate or encode before including it in structured data formats.