Crlf Injection in Sails with Firestore
Crlf Injection in Sails with Firestore — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when an attacker can inject a carriage return (CR, \r) and line feed (\n) sequence into a header or log entry, causing header splitting or log forging. In a Sails application that uses Google Firestore as a persistence layer, this risk arises when user-controlled input is reflected into Firestore document fields and later used in contexts where newline characters affect interpretation, such as HTTP response headers, log lines, or downstream parsers. Sails does not inherently sanitize data before it is written to Firestore, so if a controller passes unsanitized request parameters into a Firestore document, an attacker can embed \r\n sequences to manipulate how the data is later consumed.
For example, consider a Sails controller that stores a user-supplied note field into a Firestore collection without validation:
await Firestore.collection('notes').add({
text: req.param('note'),
createdAt: new Date()
});
If the note value contains Hello%0D%0AX-Header:%20injected, the stored document preserves the CRLF sequence. Later, if another service reads this document and uses the text field in an HTTP header or log entry, the injected CRLF can split headers or forge log lines. Firestore itself does not interpret these characters, but the vulnerability is realized when the data is output to a context that treats CRLF as a delimiter, such as response construction or log processing. This becomes a Crlf Injection vector because Sails may pass Firestore data into response headers or views without proper sanitization.
Additionally, if Sails generates URLs or redirects using data from Firestore, embedded newlines can break the redirect target into separate headers, leading to response splitting. The risk is compounded when combined with other injection issues, such as HTTP response header injection in Sails routes. Firestore does not introduce the injection but can act as a storage layer that preserves attacker-controlled newline characters until they reach a vulnerable output path.
Firestore-Specific Remediation in Sails — concrete code fixes
To mitigate Crlf Injection when using Firestore in Sails, ensure that any user input stored in or retrieved from Firestore is validated and sanitized before being used in contexts where CRLF characters have special meaning, such as HTTP headers, logs, or redirects. The following patterns demonstrate secure handling in Sails with Firestore.
Input validation and sanitization
Reject or sanitize inputs that contain carriage returns or line feeds before writing to Firestore. Use a validation rule in your Sails policy or controller to block dangerous characters:
const containsCrlf = (str) => /[\r\n]/.test(str);
module.exports = {\n friendlyName: 'Create note',
description: 'Store a user note safely.',
inputs: {
note: { type: 'string', required: true }
},
exits: {
badRequest: { statusCode: 400, description: 'Invalid input' }
},
fn: async function (inputs, exits) {
if (containsCrlf(inputs.note)) {
throw 'badRequest';
}
await Firestore.collection('notes').add({
text: inputs.note,
createdAt: new Date()
});
return exits.success({ message: 'Note stored' });
}
};
Safe output when using Firestore data in headers or redirects
When reading data from Firestore and using it in HTTP headers or redirects, sanitize newline characters by removing or replacing them. Avoid direct use of Firestore fields in header construction:
const sanitizedText = (str) => str.replace(/[\r\n]+/g, ' ');
module.exports = {
friendlyName: 'Show note',
description: 'Retrieve and display a note safely.',
fn: async function (inputs, exits) {
const doc = await Firestore.collection('notes').doc('abc123').get();
const safeText = sanitizedText(doc.get('text'));
return exits.ok({
note: safeText,
headers: {
'X-Custom': safeText
}
});
}
};
Middleware-level protection
Implement a global policy or hook in Sails to sanitize outgoing data that may include Firestore content. For example, in api/hooks/response-sanitizer/index.js, intercept responses and remove CRLF characters from values that flow into headers or logs:
module.exports.configureResponseSanitizer = function (sails) {
return function sanitize(value) {
if (typeof value === 'string') {
return value.replace(/[\r\n]+/g, ' ');
}
if (value && typeof value === 'object' && !ArrayBuffer.isView(value)) {
Object.keys(value).forEach((key) => {
value[key] = sanitize(value[key]);
});
}
return value;
};
};
Use this sanitizer before setting headers or logging Firestore-derived data. These steps ensure that CRLF characters are neutralized in the contexts where they could be weaponized, reducing the risk of Crlf Injection while preserving the utility of Firestore data within Sails.