HIGH header injectionflask

Header Injection in Flask

How Header Injection Manifests in Flask

Header injection in Flask occurs when user-supplied data flows into HTTP response headers without proper validation or encoding. Flask's architecture, while providing many security features, can still be vulnerable to header injection through several specific patterns.

The most common Flask-specific manifestation happens through make_response() and response.headers manipulation. When developers dynamically construct headers using request data, they create injection opportunities:

from flask import Flask, request, make_response
app = Flask(__name__)

@app.route('/unsafe-header')
def unsafe_header():
    user_id = request.args.get('id')
    response = make_response('Hello')
    response.headers['X-User-ID'] = user_id  # Vulnerable if user_id contains newlines
    return response

The vulnerability arises because HTTP headers are delimited by carriage return and line feed characters (\r\n). If an attacker supplies a value like 12345\r\nSet-Cookie: hacked=true, they can inject arbitrary headers into the response.

Flask's redirect() function presents another injection vector. The Location header is constructed from user input:

@app.route('/redirect-me')
def redirect_me():
    url = request.args.get('url', '/')  # Unsanitized user input
    return redirect(url)  # Vulnerable to header injection via url parameter

Flask's send_file() and send_from_directory() functions can also be exploited. These functions automatically set Content-Disposition headers based on filename parameters:

@app.route('/download')
def download():
    filename = request.args.get('file', 'default.txt')
    return send_from_directory('/uploads', filename)  # Filename can contain newlines

Additionally, Flask's error handling can inadvertently expose header injection vulnerabilities. Custom error pages that include request data in response headers create attack surfaces:

@app.errorhandler(404)
def not_found(error):
    user_agent = request.headers.get('User-Agent', '')
    response = make_response(render_template('404.html'), 404)
    response.headers['X-Debug-Info'] = user_agent  # User-Agent can contain malicious data
    return response

Flask's debug mode exacerbates these issues. When enabled, Flask includes stack traces in error responses, and if these traces incorporate request headers or parameters without sanitization, they can become injection vectors.

Flask-Specific Detection

Detecting header injection in Flask applications requires both manual code review and automated scanning. The key is identifying where user input flows into header construction.

Manual detection starts with searching for these Flask patterns:

# Patterns to search for in your Flask codebase
# 1. Direct header manipulation
response.headers['Header-Name'] = request.args.get('param')

# 2. make_response() usage
response = make_response(data)
response.headers.update(header_dict)

# 3. redirect() with dynamic URLs
return redirect(request.args.get('url'))

# 4. send_file() with dynamic parameters
return send_file(request.args.get('filename'))

# 5. Error handlers using request data
@app.errorhandler(400)
def handle_bad_request(e):
    return jsonify(error=str(e)), 400, {'X-Debug': request.remote_addr}

middleBrick provides automated detection specifically tuned for Flask applications. The scanner identifies header injection vulnerabilities by:

  • Analyzing your Flask routes and identifying dynamic header construction
  • Testing for newline characters (\r\n) in header values
  • Checking for unsafe URL construction in redirect functions
  • Examining error handlers for request data exposure
  • Scanning OpenAPI specs for header parameter definitions that could be exploited

To use middleBrick for Flask header injection detection:

# Install middleBrick CLI
npm install -g middlebrick

# Scan your Flask API endpoint
middlebrick scan https://your-flask-app.com/api/endpoint

# For CI/CD integration
middlebrick scan --threshold B --output json https://your-flask-app.com

middleBrick's Flask-specific checks include:

  • Header Injection Test: Attempts to inject newline characters into response headers
  • Redirect Validation: Tests for unsafe URL redirection and header manipulation
  • Content-Disposition Analysis: Examines file download functionality for injection
  • Debug Mode Detection: Identifies exposed debug endpoints that could leak sensitive information

The scanner provides detailed findings with severity levels and specific line numbers where vulnerabilities occur, making remediation straightforward.

Flask-Specific Remediation

Remediating header injection in Flask requires a defense-in-depth approach. Start with input validation and sanitization, then add architectural safeguards.

For direct header manipulation, always validate and sanitize user input:

from flask import Flask, request, make_response
import re
app = Flask(__name__)

# Whitelist approach for header values
ALLOWED_USER_IDS = re.compile(r'^[a-zA-Z0-9_-]+$')

def safe_header_value(value):
    """Remove newlines and validate against whitelist"""
    if not value or '\r' in value or '\n' in value:
        return None
    if not ALLOWED_USER_IDS.match(value):
        return None
    return value

@app.route('/safe-header')
def safe_header():
    user_id = request.args.get('id', 'anonymous')
    safe_id = safe_header_value(user_id) or 'anonymous'
    
    response = make_response('Hello')
    response.headers['X-User-ID'] = safe_id
    return response

For redirect functionality, implement URL validation and use Flask's built-in safety features:

from urllib.parse import urlparse, urljoin
from flask import request, redirect, url_for

# Whitelist of allowed redirect destinations
ALLOWED_HOSTS = {'yourdomain.com', 'api.yourservice.com'}

def is_safe_redirect_url(target_url):
    """Validate redirect URLs against a whitelist"""
    if not target_url:
        return False
    
    parsed = urlparse(target_url)
    if parsed.scheme not in ('http', 'https'):
        return False
    
    # Check if host is in allowed list or is relative
    if parsed.netloc and parsed.netloc not in ALLOWED_HOSTS:
        return False
    
    return True

@app.route('/safe-redirect')
def safe_redirect():
    target = request.args.get('url', url_for('index'))
    
    if not is_safe_redirect_url(target):
        return redirect(url_for('index'))  # Default to safe destination
    
    return redirect(target)

For file operations, sanitize filenames and use Flask's safe functions:

import os
from flask import send_from_directory

# Safe directory path
UPLOAD_DIRECTORY = '/var/www/uploads'

def safe_filename(filename):
    """Remove dangerous characters and path traversal"""
    # Remove newlines and carriage returns
    filename = filename.replace('\r', '').replace('\n', '')
    # Remove path traversal attempts
    filename = os.path.basename(filename)
    # Whitelist allowed characters
    if not re.match(r'^[\-_\.\w]+$', filename):
        return 'default.txt'
    return filename

@app.route('/safe-download')
def safe_download():
    filename = request.args.get('file', 'default.txt')
    safe_name = safe_filename(filename)
    
    # Ensure file exists in allowed directory
    full_path = os.path.join(UPLOAD_DIRECTORY, safe_name)
    if not os.path.exists(full_path):
        return 'File not found', 404
    
    return send_from_directory(UPLOAD_DIRECTORY, safe_name)

Implement comprehensive error handling that doesn't expose request data:

from werkzeug.exceptions import HTTPException
@app.errorhandler(HTTPException)
def handle_exception(e):
    """Handle errors without exposing request data"""
    response = e.get_response()
    response.data = json.dumps({
        'code': e.code,
        'name': e.name,
        'description': e.description
    })
    response.content_type = 'application/json'
    return response

For production deployments, disable Flask's debug mode and use proper logging:

# In your application factory or main file
app = Flask(__name__)
app.config['DEBUG'] = False  # Never enable in production
app.config['PROPAGATE_EXCEPTIONS'] = True

# Use structured logging instead of debug output
import logging
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=1)
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)

Finally, integrate middleBrick into your CI/CD pipeline to catch regressions:

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install middleBrick
        run: npm install -g middlebrick
      - name: Scan Flask API
        run: middlebrick scan https://staging.your-app.com --threshold B
      - name: Fail on high severity issues
        run: |
          middlebrick scan https://staging.your-app.com --threshold B --exit-on-fail

Frequently Asked Questions

How does header injection differ from XSS in Flask applications?
Header injection and XSS are distinct vulnerabilities with different attack vectors. Header injection manipulates HTTP response headers using newline characters to inject malicious headers like Set-Cookie or Location. XSS injects malicious scripts into HTML content that execute in users' browsers. In Flask, header injection occurs through response.header manipulation, redirect(), and send_file() functions, while XSS typically happens through template rendering or direct HTML output. Both require input validation, but header injection specifically targets the HTTP protocol structure rather than browser execution contexts.
Can middleBrick detect header injection in Flask Blueprints?
Yes, middleBrick comprehensively scans Flask applications including those using Blueprints. The scanner analyzes all registered routes, regardless of whether they're defined in the main app or Blueprints. It tests header injection across the entire API surface, examining how user input flows into response headers in every endpoint. middleBrick's analysis includes the full request-response cycle, so Blueprint-specific patterns like dynamic URL construction in redirect() calls or header manipulation in error handlers are all detected. The scanner provides findings with specific route information, making it easy to locate and fix vulnerabilities in modular Flask applications.