HIGH crlf injectionbearer tokens

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} where user_token comes 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:

  1. Identifies endpoints that accept a token parameter (e.g., /login, /refresh, or a custom auth endpoint).
  2. Submits payloads containing URL‑encoded %0d%0a, raw \r\n, and variations with multiple newlines.
  3. Observes the outgoing request from the scanner (or a reflected response) to see whether the injected characters appear unchanged in the Authorization header.
  4. 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.

Frequently Asked Questions

Can middleBrick detect CRLF injection if the token is base64‑encoded before being placed in the Authorization header?
Yes. middleBrick’s active probes send both raw and URL‑encoded CR/LF sequences. If the application decodes a base64 token after injection, the scanner’s payload will still be present in the decoded value and will be reflected in the outgoing Authorization header, allowing the scanner to flag the issue.
Is it sufficient to rely on the HTTP library to reject newline characters in header values?
Many modern libraries will throw an error when a header contains CR or LF, but not all environments do so consistently—especially when headers are built manually or when using low‑level sockets. The safest approach is to validate and strip those characters yourself before handing the value to the library, as shown in the remediation examples.