Crlf Injection in Feathersjs
How Crlf Injection Manifests in Feathersjs
Crlf Injection in Feathersjs applications typically occurs when user-controlled data flows through HTTP response headers without proper sanitization. Feathersjs, built on Express, inherits the same vulnerability patterns but with some framework-specific nuances.
The most common Feathersjs-specific scenario involves params.query data being used in response headers. Consider a Feathersjs service that logs user activity:
class ActivityService extends Service {
async create(data, params) {
const { userAgent, referer } = params.query;
// Vulnerable: query parameters directly in headers
this.app.set('X-User-Agent', userAgent);
this.app.set('X-Referer', referer);
return data;
}
}
An attacker could inject CRLF sequences by sending:
GET /api/activities?userAgent=Firefox%0D%0AX-Password: secret123
This would result in the server setting two headers:
X-User-Agent: Firefox
X-Password: secret123
Another Feathers-specific pattern involves feathers-hooks where data flows through multiple processing stages. A hook might extract data from context.params and use it in headers:
const setCustomHeaders = hook => {
const { customHeader } = hook.params.query;
hook.params.headers = {
...hook.params.headers,
'X-Custom-Header': customHeader
};
};
Feathersjs applications often use feathers-authentication with custom strategies. If a strategy uses user-provided data in authentication headers without validation, CRLF injection becomes possible:
class CustomStrategy {
async authenticate(authentication, params) {
const { customData } = authentication;
// Vulnerable: customData flows directly to headers
return this.app.service('auth').create({
headers: {
'X-Custom-Data': customData
}
});
}
}
The framework's event system can also be exploited. If a service emits events with user-controlled data that gets logged with headers:
class MessageService extends Service {
async create(data, params) {
const { userId } = params.query;
// Vulnerable: userId in event headers
this.app.emit('message.created', {
headers: {
'X-User-ID': userId
}
});
}
}
Feathersjs-Specific Detection
Detecting CRLF Injection in Feathersjs requires examining both the application code and runtime behavior. middleBrick's scanner specifically tests for this vulnerability across 12 security categories, including input validation and data exposure checks.
Code-level detection starts with identifying dangerous patterns in Feathersjs services. Look for:
// Search for these patterns in your Feathersjs codebase
const dangerousPatterns = [
/headers.*=.*[^\n]*\n/, // CRLF in headers
/set.*\n/, // Header setting with newlines
/params\.query/, // Query params in headers
/context\.params/ // Hook context in headers
];
middleBrick scans Feathersjs applications by sending payloads with encoded CRLF sequences and monitoring responses. The scanner tests common injection points:
# middleBrick CLI scan for CRLF injection
middlebrick scan https://your-feathers-app.com/api/users \
--test-crlf \
--test-headers \
--output json
The scanner specifically targets Feathersjs patterns:
params.queryvalues used in response headers- Hook context data flowing to HTTP headers
- Authentication strategy data in custom headers
- Event system data with header injection
Runtime detection involves monitoring for unexpected headers in responses. Use middleware to log and validate headers:
const crlfDetectionMiddleware = (req, res, next) => {
const originalSetHeader = res.setHeader;
res.setHeader = (name, value) => {
if (typeof value === 'string' && (value.includes('\r') || value.includes('\n'))) {
console.warn(`CRLF injection attempt detected: ${name}: ${value}`);
// Sanitize or reject
value = value.replace(/\r|\n/g, '');
}
originalSetHeader.call(res, name, value);
};
next();
};
// Add to Feathersjs app
app.use(crlfDetectionMiddleware);
middleBrick's OpenAPI analysis also checks for header definitions that might accept user input. The scanner cross-references your Feathersjs app's OpenAPI spec with runtime findings to identify header parameters that lack proper validation.
Feathersjs-Specific Remediation
Remediating CRLF Injection in Feathersjs requires a multi-layered approach. Start with input validation using Feathersjs's built-in middleware and hook system.
The most effective approach is to sanitize all user input before it reaches header generation:
const sanitizeInput = hook => {
const sanitize = (obj) => {
if (typeof obj === 'string') {
return obj.replace(/\r|\n/g, '');
} else if (typeof obj === 'object') {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, sanitize(v)])
);
}
return obj;
};
hook.data = sanitize(hook.data);
hook.params.query = sanitize(hook.params.query);
hook.params.headers = sanitize(hook.params.headers);
};
// Apply as a before hook
app.service('users').hooks({
before: {
all: [sanitizeInput]
}
});
For Feathersjs authentication strategies, validate custom data:
class SecureCustomStrategy {
async authenticate(authentication, params) {
const { customData } = authentication;
// Validate customData before use
if (typeof customData !== 'string' ||
customData.includes('\r') ||
customData.includes('\n')) {
throw new Error('Invalid custom data format');
}
return this.app.service('auth').create({
headers: {
'X-Custom-Data': customData
}
});
}
}
Use Feathersjs's validation hooks for comprehensive input sanitization:
const { authenticate } = require('@feathersjs/authentication').hooks;
const { iff, isProvider, preventChanges } = require('feathers-hooks-common');
const crlfValidator = value => {
if (typeof value === 'string' && (value.includes('\r') || value.includes('\n'))) {
throw new Error('CRLF injection detected');
}
return value;
};
app.service('messages').hooks({
before: {
create: iff(
isProvider('external'),
authenticate('jwt'),
preventChanges(true, 'headers'), // Prevent header modifications
context => {
// Validate all string fields
Object.keys(context.data).forEach(key => {
if (typeof context.data[key] === 'string') {
crlfValidator(context.data[key]);
}
});
}
)
}
});
For event systems, validate event data before emission:
class SecureMessageService extends Service {
async create(data, params) {
const { userId } = params.query;
// Validate before emitting
if (typeof userId === 'string' && (userId.includes('\r') || userId.includes('\n'))) {
throw new Error('Invalid user ID format');
}
const result = await super.create(data, params);
// Safe to emit
this.app.emit('message.created', {
userId: userId,
messageId: result.id
});
return result;
}
}
Finally, configure Feathersjs to use strict header validation:
app.set('security', {
strictHeaderValidation: true,
sanitizeHeaders: true
});
// Custom header sanitizer
app.use(function(req, res, next) {
const originalWriteHead = res.writeHead;
res.writeHead = (statusCode, headers) => {
if (headers) {
Object.keys(headers).forEach(key => {
const value = headers[key];
if (typeof value === 'string' && (value.includes('\r') || value.includes('\n'))) {
headers[key] = value.replace(/\r|\n/g, '');
}
});
}
originalWriteHead.call(res, statusCode, headers);
};
next();
});
Frequently Asked Questions
How does middleBrick specifically detect CRLF Injection in Feathersjs applications?
Can I integrate middleBrick's CRLF Injection testing into my Feathersjs CI/CD pipeline?
uses: middlebrick/middlebrick-action@v1 with inputs for your API URL, scan frequency, and failure thresholds. The Pro plan includes continuous monitoring that scans your staging APIs on a configurable schedule and sends alerts if new vulnerabilities are detected.