Header Injection in Feathersjs with Jwt Tokens
Header Injection in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Header Injection in a FeathersJS application that uses JWT tokens occurs when untrusted input from an HTTP request is reflected into response headers without validation or sanitization. This can manipulate header parsing and lead to response splitting, cache poisoning, or the injection of additional headers such as Set-Cookie, Location, or X-Origin. FeathersJS is a framework-agnostic REST and real-time API layer; it does not inherently sanitize headers, so developers must enforce strict controls when building services that rely on JWT tokens for authentication.
When JWT tokens are involved, the risk surface expands if tokens or claims are included in headers (for example, via custom headers like x-access-token or during introspection flows). An attacker may attempt to inject newline characters (CRLF, %0d%0a or \r\n) into inputs that eventually appear in headers. In FeathersJS, this can occur if the server directly uses request headers to influence token handling, such as passing a header value into token verification logic or echoing headers into error messages. Because FeathersJS commonly integrates with transports like HTTP and WebSocket, injection points may exist in hooks, services, or custom middleware that forward or reflect headers.
Consider a FeathersJS service that reads a token from a custom header and performs validation without sanitizing the header value. If an attacker can inject a newline and additional headers, they may bypass intended routing, trigger cross-origin behaviors, or manipulate caching layers between the client and server. Even when JWT tokens themselves are cryptographically signed, the surrounding transport layer must be hardened: injection at the header level can weaken trust in token origin and integrity checks. Common vectors include reflected headers in error responses, misconfigured CORS origins, or improperly handled authorization values that are concatenated into token-related logic.
Real-world attack patterns mirror classic HTTP response splitting and CRLF injection techniques mapped to the OWASP API Top 10 and CWE categories. Because FeathersJS is often used with Express under the hood, headers such as X-Forwarded-Proto or Host may be used to construct redirects or location headers. If these values are derived from user input or from token claims without strict validation, an attacker can inject malicious redirects or split responses. The presence of JWT tokens does not prevent header injection; instead, it requires careful validation of all inputs that influence token handling and header construction within the FeathersJS application and its underlying transport configuration.
Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on strict input validation, avoiding direct reflection of untrusted data into response headers, and ensuring JWT handling does not expose injection paths. In FeathersJS, use framework hooks and service logic to sanitize and normalize inputs before they affect headers or token processing. Do not trust request headers for values that influence token verification; instead, rely on explicitly configured sources and tightly controlled mappings.
Example 1: Safe retrieval of a JWT from a dedicated header with validation and no newline characters. This ensures only expected characters are accepted and prevents injection of additional headers via CRLF sequences.
// src/hooks/validate-token.js
module.exports = function validateToken() {
return async context => {
const { headers } = context;
const rawToken = headers && headers['x-access-token'] ? String(headers['x-access-token']) : '';
// Reject empty tokens and inputs containing newline or carriage return
if (!rawToken || /[\r\n]/.test(rawToken)) {
throw new Error('Invalid token');
}
// Optionally enforce token format before passing to verification
if (!/^([A-Za-z0-9_\-=]+\.){2}[A-Za-z0-9_\-=]+$/.test(rawToken)) {
throw new Error('Malformed token');
}
context.params.token = rawToken;
return context;
};
};
Example 2: Explicitly setting headers in a FeathersJS service response without reflecting untrusted input. This prevents attackers from injecting headers via user-controlled data used in token introspection or error reporting.
// src/services/secure-report/secure-report.class.js
class SecureReportService {
async find(params) {
const { user } = params;
// Do not directly copy headers or query values into response headers
const report = generateReport(user);
// If you must set headers, use a controlled set of values
params.response.setHeader('X-Content-Type-Options', 'nosniff');
params.response.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains');
return report;
}
}
Example 3: Using a FeathersJS hook to sanitize and normalize headers before they reach token-sensitive services. This approach centralizes validation and reduces the risk of accidental leakage through error messages or logging.
// src/hooks/sanitize-headers.js
module.exports = function sanitizeHeaders() {
return async context => {
const { headers } = context;
if (headers) {
Object.keys(headers).forEach(key => {
const value = headers[key];
if (typeof value === 'string') {
// Remove leading/trailing whitespace and reject control characters
const cleaned = value.trim();
if (/[\x00-\x1F\x7F]/.test(cleaned)) {
throw new Error('Invalid header value');
}
context.headers[key] = cleaned;
}
});
}
return context;
};
};
Additionally, configure your transport layer (e.g., the underlying HTTP server in your deployment) to reject requests with malformed headers containing line breaks. Combine this with a strong Content Security Policy and carefully managed CORS settings to reduce the impact of any residual injection vectors. Regularly audit hooks and services for places where headers are read or written, ensuring that JWT handling remains isolated from user-influenced header values.