Crlf Injection in Sails with Api Keys
Crlf Injection in Sails with Api Keys — 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 log entry, causing header splitting or log forging. In Sails.js, this risk is compounded when API keys are handled in a way that incorporates untrusted input into headers or response lines. For example, if a Sails controller uses an API key from a request header and directly reflects it into another header or log without sanitization, an attacker can supply a key containing \r\n sequences to inject additional headers or manipulate the protocol flow.
Consider a Sails endpoint that forwards requests to an upstream service using an API key passed via a custom header like X-API-Key. If the application constructs a new header by concatenating user input, such as a value from req.headers['x-forwarded-apikey'], an attacker can supply a key like: valid_key_value\r\nX-Admin: true. When the Sails app forwards or logs this header, the injected CRLF can create an additional header or split a log line, enabling response splitting, HTTP response smuggling, or log injection. This is especially dangerous when combined with logging mechanisms that write the API key and related headers to files, as the injected lines may appear as separate log entries, bypassing simple log-based monitoring.
In Sails, middleware and policies often process API keys and route logic in a way that may not enforce strict input validation on header values. If an API key is extracted from headers and used in templated responses or server-side logs, CRLF injection can distort structured outputs. For instance, an attacker might include \r\nSet-Cookie: session=stolen in the API key and, if the server embeds the key into a response header without sanitization, the injected line can execute in the client’s browser context. The risk is not in the API key itself being secret, but in how the Sails application handles and reflects the key when it includes newline characters.
OpenAPI specifications used by middleBrick can help identify endpoints that accept or return headers containing API keys, and the runtime checks can detect whether reflected API key values are properly sanitized. During a scan, middleBrick tests whether inputs that contain CRLF sequences are escaped before being placed into headers or logs. This is part of the broader Input Validation and Data Exposure checks that run in parallel, which help surface places where newline characters in API keys or header values can lead to injection or log forgery.
Api Keys-Specific Remediation in Sails — concrete code fixes
To mitigate Crlf Injection when handling API keys in Sails, ensure that any user-supplied or reflected values are sanitized before being used in headers, logs, or responses. The core principle is to disallow or neutralize CR and LF characters in API key values that are processed by Sails controllers, policies, or services.
One approach is to validate API key values at the point they enter your Sails application, such as in a request hook or a custom policy. For instance, you can define a policy that rejects API keys containing \r or \n:
// api/policies/validate-api-key.js
module.exports = function validateApiKey(req, res, next) {
const apiKey = req.headers['x-api-key'] || '';
if (/[\r\n]/.test(apiKey)) {
return res.status(400).send({ error: 'Invalid API key' });
}
return next();
};
Apply this policy to relevant routes in config/policies.js:
// config/policies.js
module.exports.policies = {
'*': ['validateApiKey'],
'ApiController': {
'create': ['validateApiKey', 'findOrCreate']
}
};
When you need to forward or log API keys, ensure they are normalized by stripping or encoding problematic characters. For example, if you must log the key, explicitly remove CRLF before writing to logs:
// api/helpers/logger.js
const cleanForLog = (value) => {
if (typeof value !== 'string') return value;
return value.replace(/[\r\n]+/g, '');
};
module.exports = {
logApiKey: (key) => {
const safeKey = cleanForLog(key);
sails.log.info('API key processed:', { key: safeKey });
}
};
If your Sails app proxies requests using an API key, avoid directly concatenating user input into header strings. Instead, use a map of allowed headers and explicitly set known-safe values:
// api/services/forward-service.js
const axios = require('axios');
module.exports.forwardService = async function forwardService(apiKey, userData) {
const headers = {
'X-API-Key': apiKey.replace(/[\r\n]/g, ''),
'Content-Type': 'application/json'
};
try {
const response = await axios.post('https://upstream.example.com/resource', userData, { headers });
return response.data;
} catch (err) {
sails.log.error('Forward error:', err);
throw err;
}
};
For applications using middleBrick, the CLI can be run as part of your workflow to detect endpoints where API keys are reflected in headers or logs. Use middlebrick scan <url> to identify potential injection issues and review the findings in the Web Dashboard or via JSON output. The Pro plan’s continuous monitoring can help ensure that new endpoints or changes to header handling do not reintroduce CRLF risks when API keys are involved, and the GitHub Action can gate merges if a scan detects problematic patterns.