Crlf Injection in Feathersjs with Basic Auth
Crlf Injection in Feathersjs with Basic Auth — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when an attacker can inject carriage return (CR, \r) and line feed (\n) characters into a header or status-line context, causing the server to prematurely terminate a header block and inject additional headers or split responses. In Feathersjs, this risk exists when user-controlled input is reflected in HTTP headers or status codes without proper sanitization. When Basic Auth is used, the Authorization header value (e.g., Basic base64(username:password)) is typically extracted and parsed by Feathersjs or underlying frameworks like Express. If the application uses any part of the parsed credentials—such as username or realm strings—in constructing response headers, status lines, or log entries, and does not strip or encode CR/LF characters, an attacker can inject header lines.
Basic Auth-Specific Remediation in Feathersjs — concrete code fixes
To mitigate Crlf Injection in Feathersjs with Basic Auth, ensure that any data derived from authentication inputs is sanitized before being used in header construction or status-line formatting. Below are concrete remediation steps and code examples.
1. Validate and sanitize Basic Auth parsed values
After extracting the username and password from the Basic Auth header, validate that the username does not contain CR or LF characters. Reject or normalize the input before using it in any header or status context.
// src/hooks/auth-crlf-sanitize.hooks.js
module.exports = function sanitizeAuthCrlf() {
return async context => {
const { headers } = context.params;
if (headers && headers.authorization && headers.authorization.startsWith('Basic ')) {
const base64 = headers.authorization.slice('Basic '.length);
const decoded = Buffer.from(base64, 'base64').toString('utf8');
const [username, password] = decoded.split(':');
// Reject if username contains CR or LF
if (username.includes('\r') || username.includes('\n')) {
throw new Error('Invalid credentials');
}
// Optionally rewrite context for downstream use
context.params.authUser = username;
}
return context;
};
};
Add this hook to your Feathersjs service configuration to run before authentication logic.
2. Avoid reflecting authentication data in headers or status
Do not include raw username or realm strings in custom headers or status codes. If you must include user-specific information in headers, sanitize by removing or encoding CR/LF characters.
// src/hooks/response-header-sanitize.hooks.js
const CARRIAGE_RETURN = /\r/g;
const NEWLINE = /\n/g;
module.exports = function sanitizeResponseHeaders() {
return async context => {
const { user } = context.params.authUser || {};
if (user) {
// Sanitize before using in any header value
const safeUser = user.replace(CARRIAGE_RETURN, '').replace(NEWLINE, '');
context.params.headers = {
...context.params.headers,
'X-User-Safe': safeUser
};
}
return context;
};
};
3. Configure Feathersjs transport layer safely
If you are using a custom transport (e.g., overriding send hooks), ensure that status messages and header values are sanitized. Do not directly concatenate user input into status strings.
// src/hooks/send-hooks.js
module.exports = function sendCrlfSafe() {
return async context => {
const { result, app } = context;
if (result && typeof result.send === 'function') {
const originalSend = result.send.bind(result);
result.send = function(chunk) {
// Ensure no CR/LF in custom status or headers set by app logic
const safeStatus = (context.status || 200).toString();
// Example: setting a sanitized custom header
this.setHeader('X-Status-User', (context.params.authUser || 'anon').replace(/[\r\n]/g, ''));
return originalSend(chunk);
};
}
return context;
};
};
4. Use framework-level security middleware
Combine Feathersjs hooks with helmet-style protections to strip dangerous headers and enforce safe header values. Ensure that any logging of auth events does not echo unsanitized input.
| Risk | Mitigation | Feathersjs Implementation |
|---|---|---|
| CR/LF in username used in headers | Reject or sanitize newline characters | Hook that validates authUser before use |
| Status line injection via auth-derived data | sendStatus uses unsanitized inputUse numeric status codes; avoid string concatenation |
These steps reduce the attack surface by ensuring that authentication-derived data cannot alter the structure of HTTP messages. Combine these hooks with regular scans using tools like middleBrick to detect any remaining injection risks in your Feathersjs endpoints.