Crlf Injection with Bearer Tokens
How CRLF Injection Manifests in Bearer Tokens
Bearer tokens are commonly placed in the Authorization header as Authorization: Bearer <token>. When an application builds this header by concatenating user‑supplied data (for example, a token received from a login endpoint or a refresh token) without validating or sanitizing the value, an attacker can inject carriage return (\r) and line feed (\n) characters. Those characters break the HTTP header parsing and allow the injection of additional headers or even a new request line.
Typical vulnerable code paths include:
- Node.js/Express middleware that reads a token from a cookie or query string and does
req.headers.authorization = 'Bearer ' + token. - Python Flask view that builds
headers = {'Authorization': 'Bearer ' + user_token}whereuser_tokencomes from a JSON payload. - Go HTTP client that sets
req.Header.Set("Authorization", "Bearer " + token)after reading token from an untrusted source.
If the token contains %0d%0a (URL‑encoded CRLF) or raw \r\n, the resulting header may look like:
Authorization: Bearer abc123
X-Attacker: injected
GET /admin HTTP/1.1
Host: target.com
The server (or an intermediary) may interpret the injected lines as separate headers or as a second request, enabling request smuggling, header injection, or bypassing authentication checks. Real‑world analogues include CVE‑2020‑13942 (Apache HTTP Server header injection) and CVE‑2021‑44228 (Log4j) where improper handling of user input led to header manipulation.
Bearer Tokens‑Specific Detection
Detecting CRLF injection in Bearer token usage requires checking that any value placed inside the Authorization header does not contain CR (\r) or LF (\n) characters, either raw or encoded. middleBrick’s unauthenticated black‑box scan includes an Input Validation check that actively probes header values for these characters.
When you submit an API endpoint to middleBrick (via the Dashboard, CLI, GitHub Action, or MCP Server), the scanner:
- Identifies endpoints that accept a token parameter (e.g.,
/login,/refresh, or a custom auth endpoint). - Submits payloads containing URL‑encoded
%0d%0a, raw\r\n, and variations with multiple newlines. - Observes the outgoing request from the scanner (or a reflected response) to see whether the injected characters appear unchanged in the Authorization header.
- Flags the finding if the header is transmitted with the CRLF sequence intact, indicating a lack of sanitization.
Example CLI command:
middlebrick scan https://api.example.com/auth
The resulting report will list the issue under the “Input Validation” category, provide the exact payload that triggered the injection, and show the remediation guidance (see next section). Because the scan is agentless and requires only the target URL, it can be run against staging or production APIs without deploying any agents or credentials.
Bearer Tokens‑Specific Remediation
The fix is to ensure that any user‑controlled value placed in the Bearer token is validated and stripped of CR and LF characters before header construction. Most HTTP libraries already reject header values containing newlines, but when you manually build the header you must enforce the rule yourself.
Node.js (Express)
// Middleware that validates the token before setting the header
function setBearerAuth(req, res, next) {
const rawToken = req.body.token || req.query.token || req.cookies.token;
if (typeof rawToken !== 'string') {
return res.status(400).send('Invalid token');
}
// Reject any CR or LF characters
if (/[\r\n]/.test(rawToken)) {
return res.status(400).send('Token contains illegal characters');
}
// Safe to concatenate
req.headers.authorization = `Bearer ${rawToken}`;
next();
}
Python (Flask / requests)
from flask import request, abort
@app.route('/api/data')
def protected():
token = request.json.get('token')
if not isinstance(token, str):
abort(400, 'Token must be a string')
if any(c in token for c in ('\r', '\n')):
abort(400, 'Token contains newline characters')
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get('https://internal.service/api', headers=headers)
return resp.text
Go
func bearerAuth(token string) (http.Header, error) {
if strings.ContainsAny(token, "\r\n") {
return nil, fmt.Errorf("token contains CR/LF")
}
h := make(http.Header)
h.Set("Authorization", "Bearer " + token)
return h, nil
}
Alternatively, rely on the HTTP client’s header‑setting API, which will automatically reject invalid characters. For example, in Node.js using http.request or the fetch API, passing a value with \r\n will throw an error before the request is sent.
After applying the fix, re‑run middleBrick scan to confirm that the Input Validation finding no longer appears. Continuous monitoring (available in the Pro plan) can automatically rescan the API on a schedule and alert you if the regression occurs.