Crlf Injection in Express with Api Keys
Crlf Injection in Express with Api Keys — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when user-controlled data is reflected in HTTP headers without sanitization, allowing an attacker to inject CRLF sequences (\r\n) to split headers and inject additional header lines or response body content. In Express, this often happens when API keys or other client-controlled values are used to construct custom headers or log entries without validation. For example, if an endpoint accepts an apiKey query parameter and echoes it in a response header such as X-API-Key, a newline character in the key can enable header injection. This becomes particularly risky when keys are used to drive dynamic behavior, because injected headers like Set-Cookie or Location can manipulate session handling or redirect users without their knowledge.
When combined with API keys, Crlf Injection can bypass intended access controls or leak information. An attacker may supply a key containing %0D%0A (CRLF in URL-encoded form) to smuggle headers such as X-Forwarded-For or to inject a new Set-Cookie header for session fixation. Even in logging, newline injection can fragment log lines and impair detection, making it harder to correlate events during incident review. Because the attack is unauthenticated and relies on reflection, it maps to the BFLA/Privilege Escalation and Data Exposure checks in middleBrick’s 12 security checks, which flag header manipulation and unintended data exposure.
Consider an Express route that forwards the API key into a custom header for downstream services:
app.get('/data', (req, res) => {
const apiKey = req.query.apiKey;
res.set('X-API-Key', apiKey);
res.json({ ok: true });
});
If the apiKey contains \r\n Injected-Header: malicious, the response will contain an additional header, potentially altering client or proxy behavior. MiddleBrick’s OpenAPI/Swagger analysis can highlight endpoints where user input reaches headers, while its active checks for Input Validation and Data Exposure surface such risky patterns during a scan.
Api Keys-Specific Remediation in Express — concrete code fixes
Remediation focuses on strict validation, avoiding reflection of raw keys into headers, and safe handling of identifiers. Never directly set headers with untrusted input. Instead, validate the format of API keys (e.g., alphanumeric with a fixed length) and map them to internal identifiers that are safe to use. If you must return an echo for debugging, encode or omit the raw key entirely.
Below are concrete, safe patterns for Express routes that work with API keys.
1) Validate and do not reflect raw keys in headers
const crypto = require('crypto');
function isValidApiKey(key) {
return /^[A-Za-z0-9\-_]{32}$/.test(key);
}
app.get('/data', (req, res) => {
const apiKey = req.query.apiKey;
if (!apiKey || !isValidApiKey(apiKey)) {
return res.status(401).json({ error: 'Invalid API key' });
}
// Use a deterministic mapping to an internal token or lookup the scope
const internalToken = crypto.createHash('sha256').update(apiKey).digest('hex');
res.json({ token: internalToken });
});
This approach ensures that only well-formed keys are accepted and prevents newlines or control characters from being processed. The internal token is derived safely and does not expose the original key in headers.
2) Use a fixed allowlist for header values
app.get('/resource', (req, res) => {
const apiKey = req.query.apiKey;
if (!apiKey || !isValidApiKey(apiKey)) {
return res.status(401).json({ error: 'Invalid API key' });
}
// Safe: derived value used in a controlled header
const safeValue = `key_${crypto.createHash('sha256').update(apiKey).digest('hex').slice(0, 8)}`;
res.set('X-Key-Summary', safeValue);
res.json({ ok: true });
});
By deriving a short, safe summary rather than reflecting the raw key, you eliminate injection risks while still providing traceability. This pattern aligns with the Property Authorization checks in middleBrick, which verify that data exposure respects defined policies.
Additionally, leverage Express middleware to reject requests containing suspicious sequences early:
app.use((req, res, next) => {
const combined = Object.values(req.query).concat(Object.values(req.headers)).join(' ');
if (/[\r\n]/.test(combined)) {
return res.status(400).json({ error: 'Invalid characters in request' });
}
next();
});
This preemptive validation reduces the attack surface across all endpoints. For continuous assurance, integrate middleBrick’s CLI (middlebrick scan <url>) or GitHub Action to fail builds when header injection patterns are detected in your OpenAPI spec or runtime behavior.