Crlf Injection in Strapi with Bearer Tokens
Crlf Injection in Strapi with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when user-controlled data is reflected in HTTP headers without proper sanitization, allowing an attacker to inject newline characters (CRLF = \r\n). In Strapi, this risk can manifest when an API response includes values from request inputs—such as query parameters or headers—directly in custom response headers or in JSON fields that an attacker can influence via other vectors.
When Bearer Tokens are involved, the token value itself is typically transmitted in the Authorization header (Authorization: Bearer
This combination is particularly dangerous because Bearer Tokens often contain sensitive information; leaking them via response headers or reflected payloads can lead to token theft. Even if the token remains intact, injected headers like Set-Cookie or Location can enable session fixation, open redirects, or bypass CSRF protections. In a black-box scan, such behavior would be flagged by the Authentication and Data Exposure checks in middleBrick, which tests how inputs propagate through headers and whether secrets are inadvertently reflected.
Consider a Strapi endpoint that echoes a caller-supplied label into a custom header. A request like GET /products?label=foo%0D%0ASet-Cookie:session=123 results in the server adding two headers: X-Entity-Id: foo and Set-Cookie: session=123. If the Authorization header contains a Bearer token, and a plugin carelessly includes parts of the request in headers or logs, an attacker may learn the token or manipulate authorization checks via the injected header chain.
middleBrick tests this attack surface by scanning unauthenticated endpoints and analyzing OpenAPI specs alongside runtime behavior, identifying places where inputs influence headers. Findings will highlight header injection points and provide remediation guidance to ensure tokens and other sensitive data are never reflected or controllable via CRLF injection.
Bearer Tokens-Specific Remediation in Strapi — concrete code fixes
To mitigate Crlf Injection when using Bearer Tokens in Strapi, ensure that any user input used in headers is strictly validated and sanitized. Never directly reflect request-controlled data into response headers. Below are concrete remediation patterns and Strapi code examples.
1. Avoid reflecting user input in custom headers
If you must set custom headers, derive values from trusted sources (e.g., entity IDs from the database) and do not include raw user input. Do not concatenate headers from request parameters.
// BAD: Reflecting user-controlled label into a header
strapi.db.lifecycles.subscribe('api::product.product', 'afterCreate', async ({ result }) => {
const label = result.label; // user-controlled
// Risk: label may contain \r\n and be appended to headers by middleware
strapi.log.info(`Product label: ${label}`);
});
// GOOD: Use a sanitized, non-user value for headers
strapi.db.lifecycles.subscribe('api::product.product', 'afterCreate', async ({ result }) => {
const safeHeaderValue = `product-${result.id}`;
// Use safeHeaderValue in internal logic, never echo raw user input into headers
strapi.log.info(`Product id: ${safeHeaderValue}`);
});
2. Sanitize any reflected headers explicitly
If you must include user data in headers, strip or encode CRLF characters. In Strapi middleware or policies, enforce this before headers are sent.
// policy: sanitize-header.js
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
const raw = ctx.request.header['x-entity-id'];
if (raw) {
// Remove CRLF characters to prevent header injection
const sanitized = raw.replace(/[\r\n]+/g, '');
ctx.set('X-Entity-Id', sanitized);
}
await next();
};
};
Apply this policy to relevant routes. This ensures that even if an attacker supplies \r\n via x-entity-id, the header value is neutralized before being set.
3. Secure Bearer Token handling and response headers
Ensure tokens are only transmitted over HTTPS and never echoed in headers or logs. Configure Strapi to avoid including Authorization in any debug or custom headers.
// Example: safe request within Strapi service (no reflection of Authorization header)
async fetchUserData(ctx) {
const authHeader = ctx.request.header.authorization; // Bearer token present
if (!authHeader || !authHeader.startsWith('Bearer ')) {
ctx.throw(401, 'Unauthorized');
}
const token = authHeader.split(' ')[1];
// Do NOT set any header based on token content
// Do NOT log token
const user = await strapi.entityService.findOne('api::user.user', userId, { populate: '*' });
ctx.body = { id: user.id, username: user.username };
}
In this pattern, the token is used only for authentication and never placed into response headers, logs, or any user-influenced output. This prevents both accidental leakage and CRLF-based injection via token-derived data.
4. Validate and enforce strict header policies in Strapi admin
Review custom headers defined in Strapi admin and server configuration. Remove any dynamic insertion of request-derived values into headers such as X-Forwarded-For, X-Entity-Id, or custom metadata unless strictly necessary and sanitized.
5. Testing and verification
Verify fixes by sending requests with CRLF sequences and confirming headers are not split or injected.
# Example curl to test injection attempt (should not create new headers)
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" \
-H "X-Entity-Id: foo%0D%0ASet-Cookie:auth=evil" \
http://localhost:1337/api/products
Inspect response headers to ensure no injected Set-Cookie or additional headers appear. middleBrick scans can validate that such injection attempts are detected and reported under Authentication and Data Exposure checks.