Header Injection with Api Keys
How Header Injection Manifests in Api Keys
Header injection in API keys occurs when untrusted input flows into HTTP header values without proper validation. This manifests in several critical ways specific to API key handling.
The most common scenario involves API keys being constructed from user input or database values. Consider a system where users can create custom API keys with prefixes:
// Vulnerable pattern - user input flows directly into Authorization header
const userId = req.params.userId;
const userKey = await db.getUserApiKey(userId);
const customPrefix = req.body.prefix || 'Bearer';
const authHeader = `${customPrefix} ${userKey}`;
res.setHeader('Authorization', authHeader);
An attacker could submit a prefix like Bearer xyz
X-Injected: malicious-value, creating a header injection that adds arbitrary headers to the response.
Another manifestation occurs in API key rotation systems. When rotating keys, if the old key is concatenated with metadata:
// Vulnerable rotation logic
const rotateKey = async (userId) => {
const oldKey = await db.getApiKey(userId);
const rotationData = `Rotated:${Date.now()}:${oldKey}`;
const newKey = crypto.randomBytes(32).toString('hex');
await db.updateApiKey(userId, newKey);
// Header injection point - rotation data flows to client
res.setHeader('X-Rotation-Info', rotationData);
return newKey;
};
If oldKey contains newline characters (common in base64 or hex keys), an attacker who can influence key generation could inject arbitrary response headers.
API key forwarding through proxy services creates another injection vector. When a service forwards requests with client API keys:
// Vulnerable proxy implementation
app.post('/forward', async (req, res) => {
const clientKey = req.headers['x-client-key'];
const targetUrl = 'https://api.example.com/endpoint';
const headers = {
'Authorization': `Bearer ${clientKey}`,
'X-Forwarded-For': req.ip
};
// Header injection via malformed clientKey
const response = await axios.post(targetUrl, req.body, { headers });
res.send(response.data);
});
A client key containing Bearer valid
X-Injected: value would add the injected header to the forwarded request, potentially exposing internal services or bypassing security controls.
Api Keys-Specific Detection
Detecting header injection in API key systems requires both static analysis and runtime scanning. Here are Api Keys-specific detection approaches:
Static Analysis Patterns
Scan for these vulnerable patterns in your codebase:
// Search for these anti-patterns
const regexPatterns = [
/Authorization.*=.*\$\{.*\}/, // Dynamic header construction
/Bearer\s+[^\s\n\r]+/, // Header splitting attempts
/[^\w\d\-\+\/\=]/, // Invalid characters in base64 keys
/\n|\r/, // Newline characters
];
Runtime Header Validation
Implement strict validation before using API keys in headers:
const validateApiKeyHeader = (key) => {
// Check for newline characters
if (key.includes('\n') || key.includes('\r')) {
throw new Error('Invalid API key format');
}
// Validate base64 format if applicable
if (isBase64(key)) {
const decoded = Buffer.from(key, 'base64').toString('utf8');
if (decoded.includes(':')) {
throw new Error('Potential header injection detected');
}
}
return true;
};
middleBrick Scanning
middleBrick's API security scanner includes specific checks for header injection vulnerabilities in API key handling:
| Check Type | What It Tests | Api Keys Relevance |
|---|---|---|
| Header Injection | Tests for newline characters in headers | Detects malformed API keys that could inject headers |
| Input Validation | Validates header parameter sanitization | Ensures API keys are properly validated before use |
| Property Authorization | Checks if headers are properly scoped | Verifies API key headers aren't exposed to unauthorized users |
To scan with middleBrick:
npx middlebrick scan https://api.example.com/auth
The scanner tests your API endpoints with malformed API keys containing newline characters and special sequences to detect header injection vulnerabilities.
Api Keys-Specific Remediation
Remediating header injection in API key systems requires defense-in-depth approaches. Here are Api Keys-specific fixes:
Strict Header Construction
Always validate and sanitize before constructing headers:
const createAuthHeader = (apiKey) => {
// Validate API key format
if (!isValidApiKeyFormat(apiKey)) {
throw new Error('Invalid API key format');
}
// Remove any control characters
const sanitizedKey = apiKey.replace(/[^\w\d\-\+\/\=]/g, '');
// Use a constant prefix - never allow user control
return `Bearer ${sanitizedKey}`;
};
const isValidApiKeyFormat = (key) => {
// Check length (typical API keys are 32-64 chars)
if (key.length < 16 || key.length > 128) return false;
// Check for invalid characters
if (/[^\w\d\-\+\/\=:\.]/.test(key)) return false;
// Check for newline characters
if (key.includes('\n') || key.includes('\r')) return false;
return true;
};
Header Injection Prevention Middleware
Implement middleware that blocks requests with suspicious API keys:
const headerInjectionPrevention = (req, res, next) => {
const suspiciousHeaders = ['Authorization', 'X-Api-Key'];
for (const header of suspiciousHeaders) {
const value = req.get(header);
if (value && (value.includes('\n') || value.includes('\r'))) {
return res.status(400).json({
error: 'Invalid header format',
details: 'Header injection attempt detected'
});
}
}
next();
};
app.use(headerInjectionPrevention);
API Key Rotation with Validation
When implementing rotation, ensure old keys can't be used for injection:
const rotateApiKey = async (userId) => {
const oldKey = await db.getApiKey(userId);
// Validate old key before using it
if (!isValidApiKeyFormat(oldKey)) {
throw new Error('Invalid API key format during rotation');
}
const newKey = generateSecureApiKey();
await db.updateApiKey(userId, newKey);
// Never expose old keys in headers or responses
return { newKey, rotationTimestamp: Date.now() };
};
Proxy Service Hardening
For services that forward API keys, implement strict validation:
const forwardRequestWithValidation = async (req) => {
const clientKey = req.headers['x-client-key'];
// Validate client key format
if (!isValidApiKeyFormat(clientKey)) {
throw new Error('Invalid client API key format');
}
// Remove any existing Authorization header from client
delete req.headers['authorization'];
// Add our own validated header
const validatedHeaders = {
...req.headers,
'Authorization': createAuthHeader(clientKey)
};
return await axios.post(targetUrl, req.body, { headers: validatedHeaders });
};
Monitoring and Alerting
Set up monitoring for header injection attempts:
const monitorHeaderInjectionAttempts = (req, res, next) => {
const authHeader = req.get('Authorization');
if (authHeader && (authHeader.includes('\n') || authHeader.includes('\r'))) {
// Log and alert
console.warn('Header injection attempt detected:', {
ip: req.ip,
userAgent: req.get('User-Agent'),
timestamp: new Date().toISOString()
});
// Send alert to monitoring system
alertService.sendAlert({
type: 'SECURITY',
severity: 'HIGH',
message: 'Header injection attempt detected',
metadata: { ip: req.ip }
});
}
next();
};
Frequently Asked Questions
How can I test if my API keys are vulnerable to header injection?
%0A (newline) or %0D (carriage return) characters and observing if they create additional headers in the response.