Crlf Injection in Feathersjs with Firestore
Crlf Injection in Feathersjs with Firestore — 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 an HTTP header or log entry. In a Feathersjs application that uses Firestore as the data store, this typically arises when user-controlled input is reflected into headers, response lines, or structured data that later influences logging or downstream parsers. Feathersjs does not inherently sanitize inputs before they are used to construct responses or interact with services, and Firestore documents often contain fields that may be concatenated into log lines, error messages, or used in dynamically built queries.
When Feathersjs hooks or service methods pass unchecked user input into Firestore document fields, and those fields are later rendered into HTTP responses or log entries without proper escaping, CR and LF characters can alter the intended structure. For example, if a Firestore document stores a user-supplied "note" field that is later included in a JSON response, and that note contains \r\n, an attacker can inject new headers or break log formatting if the response is improperly handled by an intermediate proxy or logging system. Additionally, if Firestore data is used to construct URLs, file paths, or command-like strings within server-side logic, injected line breaks can lead to header splitting in outbound HTTP requests or command injection in backend processes that consume Firestore data.
Another vector involves logging and monitoring integrations. Feathersjs may log request and response metadata, including Firestore document IDs or fields. If a Firestore field contains \r\n, an attacker can inject fake headers into log entries, potentially obscuring real events or causing log-based monitoring tools to misinterpret event boundaries. In distributed systems where Firestore documents are shared across services, unsanitized line breaks can also interfere with serialization formats that assume line-based separation, such as certain CSV exports or streaming protocols. The combination of Feathersjs’s flexible service layer and Firestore’s schema-less document model increases the surface area for unintended data concatenation, making input validation and output encoding essential.
Firestore-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on strict input validation, context-aware output encoding, and defensive handling of Firestore data within Feathersjs hooks and services. Always validate and sanitize user input before writing to Firestore, and avoid directly embedding user data into headers, log lines, or dynamic commands. Use libraries designed for safe header construction and structured logging to prevent accidental injection.
Input validation and sanitization
Validate incoming data in Feathersjs hooks to reject or neutralize CR and LF characters in fields that must not contain them. For free-text fields where line breaks are not semantically meaningful, strip or encode these characters. For fields where line breaks are expected (such as multi-line notes), ensure downstream consumers handle them safely and never re-emit them into HTTP headers or log streams without encoding.
// Feathersjs before hook: validate and sanitize note field
const validateNote = context => {
const { text } = context.data || {};
if (typeof text !== 'string') {
throw new Error('Note text must be a string');
}
// Reject control characters that could enable injection
if (/[\r\n]/.test(text)) {
throw new Error('Note text must not contain line breaks');
}
context.data = { ...context.data, text };
return context;
};
// Apply hook in your notes service
const notesService = app.service('notes');
notesService.hooks({
before: {
create: [validateNote],
update: [validateNote]
}
});
Safe Firestore document writes
When writing to Firestore, ensure that string fields are normalized or encoded if they may later be used in contexts where CR/LF could be misinterpreted. For structured metadata, prefer explicit field types and avoid storing concatenated header-like values. If you must store user input that may contain line breaks, consider encoding them (e.g., using Base64 or percent-encoding) and decoding only in safe contexts.
// Firestore write with sanitized input in a Feathersjs service hook
const sanitizeForFirestore = context => {
const payload = context.data || {};
const safePayload = Object.keys(payload).reduce((acc, key) => {
let value = payload[key];
if (typeof value === 'string') {
// Replace CR/LF to prevent header/log injection when this field is used externally
value = value.replace(/[\r\n]/g, ' ');
}
acc[key] = value;
return acc;
}, {});
context.data = safePayload;
return context;
};
const notesService = app.service('notes');
notesService.hooks({
before: {
create: [sanitizeForFirestore],
patch: [sanitizeForFirestore]
}
});
// Example Firestore document write using the Firebase SDK within a Feathersjs hook
const firestore = app.get('firestore');
notesService.hooks({
after: {
async create(result, context) {
const docRef = firestore.collection('notes').doc(result.id);
await docRef.set({
title: context.data.title,
content: context.data.content,
// Safe: line breaks removed or replaced earlier
updatedAt: new Date()
});
return result;
}
}
});
Response and logging safety
Ensure that Firestore document fields included in HTTP responses are encoded for the target context (e.g., JSON serialization is generally safe, but avoid embedding user data into raw HTTP headers). Use structured logging that treats each log entry as a single logical line, and avoid concatenating Firestore fields directly into log messages that could be parsed as multi-line entries.
// Safe logging of Firestore data in Feathersjs
app.service('notes').hooks({
after: {
async get(result, context) {
// Avoid concatenating user data into log lines that may be parsed as headers
console.log('Note retrieved', { id: result.id, title: result.title });
return result;
}
}
});