HIGH header injectionflaskbearer tokens

Header Injection in Flask with Bearer Tokens

Header Injection in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Header Injection in Flask with Bearer Tokens occurs when user-controlled input is reflected into HTTP response headers without validation or encoding, and those headers include Authorization values such as Bearer tokens. This can lead to header manipulation, session fixation, or token leakage depending on how Flask applications construct responses and how intermediaries (proxies, CDNs, or browsers) handle headers.

In Flask, developers commonly set or forward headers based on request data (e.g, copying an Authorization header from an upstream service or reflecting a token into a custom header for downstream use). If the application directly embeds user input into headers without strict allowlists or proper escaping, an attacker can inject newline characters (%0A, %0D) to create additional headers such as Set-Cookie, Location, or X-Content-Type-Options. Because Bearer tokens often appear in Authorization headers, an injected header can duplicate or override security directives, bypassing intended protections.

For example, consider an endpoint that forwards a token from an incoming Authorization header into a custom X-Auth-Token header without sanitization. An attacker could supply a token containing a newline and a crafted header (e.g., X-Token: abc\r\nSet-Cookie: session=hijacked), leading the server to emit two headers. If the injected header is interpreted by downstream components, it may change behavior in the browser, a reverse proxy, or an API gateway. This can expose tokens in logs, enable cross-site request forgery via injected cookies, or facilitate open redirect scenarios if combined with Location header injection.

Flask’s development server is not designed to mitigate such injection at the framework level; responsibility falls on the developer to validate and sanitize any data that influences headers. Common root causes include naive string concatenation when building Authorization values, failure to reject control characters in token-like inputs, and overly permissive header-copying logic. Even when tokens originate from a client, they should never be echoed back verbatim in response headers without strict checks because doing so can disclose sensitive material in logs or to downstream observers.

Because middleBrick scans test unauthenticated attack surfaces and perform OpenAPI/Swagger spec analysis with full $ref resolution, they can surface endpoints where header construction logic may expose Bearer tokens through injection paths. Findings include indicators such as reflected Authorization values in custom headers and missing input constraints on token formats, which align with OWASP API Top 10 categories relevant to security misconfiguration and data exposure.

Bearer Tokens-Specific Remediation in Flask — concrete code fixes

Remediation focuses on strict input validation, avoiding reflection of raw tokens into headers, and ensuring Authorization values are handled server-side only. Do not copy client-provided Authorization headers into response headers or logs. If you must forward tokens to downstream services, use server-side storage or short-lived session mappings instead of direct reflection.

1) Validate and sanitize all inputs that could reach headers. Reject or normalize strings containing carriage return (\r) and line feed (\n) characters before any header assignment.

import re
from flask import Flask, request, jsonify

app = Flask(__name__)

# Allow only token-safe characters (base64url, hyphen, underscore, no whitespace or control chars)
SAFE_TOKEN_RE = re.compile(r'^[A-Za-z0-9\-._~+/=]+$')

def is_safe_token(value: str) -> bool:
    return bool(SAFE_TOKEN_RE.fullmatch(value))

@app.before_request
def reject_malformed_headers():
    auth = request.headers.get('Authorization', '')
    if auth.startswith('Bearer '):
        token = auth[7:].strip()
        if not is_safe_token(token):
            return jsonify({'error': 'invalid_token'}), 400

2) Do not reflect Bearer tokens in custom response headers. Instead, use opaque references mapped server-side. For example, store a token-to-user mapping in a secure server-side cache and reference it by a random session ID.

import secrets
from flask import Flask, request, make_response

app = Flask(__name__)
# server-side mapping, e.g., in Redis or in-memory store
server_token_map = {}

@app.route('/proxy')
def proxy():
    auth = request.headers.get('Authorization', '')
    if not auth.startswith('Bearer '):
        return {'error': 'missing_bearer'}, 401
    token = auth[7:].strip()
    if not is_safe_token(token):
        return {'error': 'invalid_token'}, 400
    # Map token to an opaque reference without echoing the token in headers
    session_id = secrets.token_urlsafe(16)
    server_token_map[session_id] = token
    resp = make_response(jsonify({'status': 'proxied'}))
    resp.headers['X-Session'] = session_id  # safe, non-sensitive reference
    return resp

3) When constructing Authorization headers for outgoing requests, ensure values are built from trusted sources only and never include user-controlled newline characters. Use standard libraries for HTTP requests and avoid manual string assembly for header values.

import requests

def forward_to_upstream(token: str):
    if not is_safe_token(token):
        raise ValueError('unsafe token')
    headers = {'Authorization': f'Bearer {token}'}
    # requests library does not allow raw newline injection in header values
    # but we still validate to prevent accidental misuse
    resp = requests.get('https://api.example.com/data', headers=headers)
    return resp.json()

4) Harden Flask’s handling of incoming headers by disabling unwanted header forwarding and explicitly defining which headers are allowed. Use configuration to strip or ignore sensitive headers from being passed through to responses.

from flask import Flask
app = Flask(__name__)
# Ensure sensitive headers are not inadvertently exposed
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False

@app.after_request
def remove_sensitive_headers(response):
    response.headers.pop('Authorization', None)
    response.headers.pop('Proxy-Authorization', None)
    return response

These practices reduce the risk of header injection and unintended exposure of Bearer tokens. They also align with secure handling patterns recommended in the OWASP API Security Top 10 and support compliance mappings available in tools such as middleBrick, which can highlight header manipulation risks and provide remediation guidance in scan reports.

Frequently Asked Questions

Why is reflecting a Bearer token in a custom response header risky?
Reflecting a Bearer token in a custom response header can expose the token in logs, browser history, or to unauthorized clients if the header is inadvertently shared. It also enables header injection attacks where newline characters can create additional headers like Set-Cookie, leading to session fixation or cross-site request forgery.
How does middleBrick help detect header injection risks involving Bearer tokens?
middleBrick scans unauthenticated attack surfaces and analyzes OpenAPI/Swagger specs with full $ref resolution. It identifies endpoints where Authorization values may be reflected into custom headers, highlights missing input validation on token formats, and maps findings to frameworks such as OWASP API Top 10 to prioritize remediation.