Header Injection in Fiber with Jwt Tokens
Header Injection in Fiber with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Header Injection in a Fiber application that uses JWT tokens typically arises when user-controlled input is reflected into HTTP response headers without validation or encoding. For example, if a route reads a header value such as X-Request-ID from the incoming request and passes it directly into the outgoing response via ctx.Set(), an attacker can inject additional header lines like
or
. This can split the response headers and body, enabling response smuggling, header manipulation, or bypass of security middleware that relies on header values.
When JWT tokens are involved, one common pattern is to forward or mirror a token from an incoming header (e.g., Authorization: Bearer <token>) into another header for logging, routing, or propagation. If the application copies the token value from the request into a custom response header without strict validation, it creates a vector where newline characters inside the token (which are non-standard but possible in some encodings or error messages) can be used to inject crafted headers. Because JWT tokens are often treated as opaque by applications, developers may assume they are safe and skip normalization or canonicalization, inadvertently allowing injection.
Another scenario involves parsing the Authorization header itself. If the server uses a simple string split on whitespace or commas to extract the token, an injected newline or carriage return can cause the parser to misinterpret the token boundary, leading to incorrect authentication decisions or token leakage into unintended headers. This can expose the application to security weaknesses such as bypassing rate limiting tied to the token or misrepresenting the authenticated subject in logs and downstream services.
For instance, an attacker might send a request with a malformed Authorization header such as:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c X-Injection: injected-value
If the application echoes parts of the Authorization header into another header, the newline before X-Injection can cause the injected header to be interpreted as separate response headers. This behavior violates the principle of strict header handling and can be detected by middleBrick’s 12 security checks, which include Input Validation and Header/BOLA testing as part of its unauthenticated black-box scan.
Jwt Tokens-Specific Remediation in Fiber — concrete code fixes
To remediate Header Injection risks when working with JWT tokens in Fiber, ensure that any user-controlled data reflected into headers is strictly validated, canonicalized, and encoded. Do not directly copy tokens or header fragments into response headers. Instead, treat the Authorization header as an opaque identifier and avoid echoing its contents. Use strict parsing that tolerates only the expected format and reject any input containing newline or carriage return characters.
Below are concrete code examples for safe handling of JWT tokens in Fiber.
1. Strict Authorization header parsing
Parse the Authorization header carefully, ensuring it matches the expected scheme and token format. Reject malformed inputs.
const jwt = require('jsonwebtoken');
const express = require('express'); // context: Fiber uses similar patterns
const app = express();
app.use((req, res, next) => {
const auth = req.headers['authorization'];
if (auth) {
const parts = auth.split(' ');
if (parts.length === 2 && parts[0] === 'Bearer') {
const token = parts[1];
// Reject tokens with newline or carriage return
if (/[\r\n]/.test(token)) {
return res.status(400).send('Invalid token');
}
// Optionally verify structure without validating signature for checks
try {
const decoded = jwt.decode(token, { complete: true });
if (!decoded || !decoded.header || !decoded.payload) {
return res.status(400).send('Invalid token format');
}
// Attach decoded payload for downstream use (do not forward raw token)
req.user = decoded.payload;
} catch (err) {
return res.status(400).send('Invalid token');
}
} else {
return res.status(400).send('Invalid authorization format');
}
} else {
return res.status(401).send('Authorization header missing');
}
next();
});
2. Avoid echoing tokens into response headers
Do not set response headers using values derived from the token. If you need to propagate a non-sensitive identifier, use a sanitized, server-generated value.
app.get('/profile', (req, res) => {
if (!req.user) {
return res.status(401).send('Unauthorized');
}
// Use a server-generated request ID instead of the token
const requestId = crypto.randomUUID();
res.setHeader('X-Request-ID', requestId);
res.json({ profile: req.user });
});
3. Validate and sanitize any custom headers derived from tokens
If you must propagate a transformed value, ensure it is normalized and stripped of control characters.
function sanitizeHeaderValue(value) {
if (typeof value !== 'string') return '';
// Remove CR, LF, and other control characters
return value.replace(/[\r\n\x00-\x1F\x7F]/g, '');
}
app.post('/log', (req, res) => {
const incoming = req.headers['x-token-fingerprint'];
if (incoming) {
const safeValue = sanitizeHeaderValue(incoming);
// Use safeValue only for non-security logging
console.log('Fingerprint:', safeValue);
}
res.sendStatus(204);
});
These practices align with the checks performed by middleBrick, including Input Validation, Property Authorization, and BOLA testing. They help ensure that JWT tokens are handled as secure identifiers rather than data that can be reflected into headers, reducing the risk of injection and response splitting.