HIGH bleichenbacher attackflask

Bleichenbacher Attack in Flask

How Bleichenbacher Attack Manifests in Flask

The Bleichenbacher attack exploits how RSA PKCS#1 v1.5 padding is handled during decryption, allowing an attacker to gradually recover plaintext by observing whether decryption attempts succeed or fail. In Flask applications, this manifests in several specific ways that developers often overlook.

The most common scenario involves Flask's default error handling for malformed or invalid encrypted data. When a Flask route receives an encrypted payload—typically in API endpoints handling payment processing, authentication tokens, or encrypted session data—the application must decrypt it before processing. Flask's default behavior is to return generic error responses for decryption failures, but the timing differences between various failure modes create a timing oracle.

Consider a Flask endpoint that decrypts incoming RSA-encrypted data:

from flask import Flask, request, jsonify
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
import time

app = Flask(__name__)

private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

@app.route('/decrypt', methods=['POST'])
def decrypt_endpoint():
    encrypted_data = request.data
    
    start_time = time.time()
    try:
        decrypted = private_key.decrypt(
            encrypted_data,
            padding.PKCS1v15()
        )
        duration = time.time() - start_time
        return jsonify({
            'decrypted': decrypted.decode(),
            'processing_time': duration
        })
    except Exception as e:
        duration = time.time() - start_time
        return jsonify({
            'error': 'Decryption failed',
            'processing_time': duration
        })

The vulnerability lies in the timing information exposed through the processing_time field. Different types of padding errors take different amounts of time to process, allowing an attacker to distinguish between "wrong padding format" and "invalid padding bytes." The PKCS1v15 padding is particularly vulnerable because it doesn't use constant-time operations.

Another Flask-specific manifestation occurs with Flask-Session when using encrypted cookie sessions. The default session interface doesn't implement constant-time comparison for session integrity checks, potentially exposing timing differences that could be exploited in conjunction with Bleichenbacher-style attacks.

Flask-RESTful and Flask-RESTx APIs that handle encrypted authentication tokens are also vulnerable when they implement custom decryption logic without constant-time padding validation. The problem compounds when these APIs return different HTTP status codes or error messages based on the type of decryption failure, providing an oracle without even requiring timing analysis.

The attack becomes practical when Flask applications run on shared infrastructure where an attacker can measure response times from their own requests. Even small timing differences—microseconds to milliseconds—accumulate over thousands of queries to gradually recover the entire plaintext.

Flask-Specific Detection

Detecting Bleichenbacher vulnerabilities in Flask applications requires both static analysis and dynamic testing. For static analysis, middleBrick's API security scanner specifically targets this vulnerability pattern by examining your Flask application's cryptographic implementations.

When scanning a Flask API endpoint that handles encrypted data, middleBrick analyzes the code path for several critical indicators:

First, it checks for the use of PKCS1v15 padding instead of OAEP padding. The scanner searches for imports from cryptography.hazmat.primitives.asymmetric.padding and flags any use of PKCS1v15. Here's what middleBrick detects:

# Vulnerable pattern - middleBrick flags this
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15

# Secure pattern - middleBrick confirms this is safe
from cryptography.hazmat.primitives.asymmetric.padding import OAEP, MGF1

Second, middleBrick examines error handling patterns. It looks for Flask routes that catch generic exceptions around decryption operations and return timing information or error details that could serve as an oracle. The scanner specifically identifies patterns like:

try:
    decrypted = key.decrypt(data, padding)
    # Success path
except Exception:
    # Failure path - vulnerable if timing differs

Third, middleBrick performs active probing of your Flask endpoints. It sends crafted RSA-PKCS#1 v1.5 ciphertexts with slight modifications and measures response characteristics. The scanner looks for:

  • HTTP status code variations between different failure types
  • Response time variations that correlate with padding validation steps
  • JSON field differences that reveal decryption success/failure states
  • Logging patterns that might expose sensitive decryption information

For Flask applications using Flask-Session with encrypted cookies, middleBrick specifically checks the session interface implementation for constant-time comparison vulnerabilities. It also examines any custom middleware that handles encrypted authentication tokens.

The scanner generates a detailed report showing which endpoints are vulnerable, the specific code locations, and the exact nature of the oracle being exposed. For Flask applications, middleBrick provides Flask-specific remediation guidance, including recommended code changes and library alternatives.

middleBrick's LLM security module also checks for any AI/ML endpoints that might be processing encrypted training data or model parameters, as these can introduce additional Bleichenbacher attack surfaces when implemented in Flask applications.

Flask-Specific Remediation

Remediating Bleichenbacher vulnerabilities in Flask requires both immediate fixes and architectural changes. The most critical step is eliminating PKCS#1 v1.5 padding entirely in favor of OAEP padding with proper MGF1 mask generation.

Here's the secure Flask implementation:

from flask import Flask, request, jsonify
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
import time
from cryptography.hazmat.primitives.asymmetric.padding import OAEP, MGF1

app = Flask(__name__)

private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

@app.route('/decrypt', methods=['POST'])
def decrypt_endpoint():
    encrypted_data = request.data
    
    # Use OAEP padding with MGF1 - secure against Bleichenbacher
    try:
        decrypted = private_key.decrypt(
            encrypted_data,
            OAEP(
                mgf=MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        return jsonify({'decrypted': decrypted.decode()})
    except Exception:
        # Generic error - no timing information, no oracle leakage
        return jsonify({'error': 'Decryption failed'}), 400

The key changes: OAEP padding instead of PKCS1v15, and generic error handling without timing information. For even stronger security, implement constant-time comparisons for any post-decryption validation:

from cryptography.hazmat.primitives import constant_time

# After decryption, use constant-time comparison for any validation
expected_signature = b"valid_token"
if not constant_time.bytes_eq(decrypted[:len(expected_signature)], expected_signature):
    return jsonify({'error': 'Validation failed'}), 400

For Flask-Session users, switch to server-side sessions or implement constant-time session integrity checks. Here's a secure Flask-Session wrapper:

from flask import Flask, session
from flask_session import Session
import hmac
import hashlib

app = Flask(__name__)
app.config['SESSION_TYPE'] = 'filesystem'  # Avoid encrypted cookies
Session(app)

# For any encrypted data handling, use constant-time validation
def validate_encrypted_payload(payload, expected_hash):
    computed_hash = hmac.new(
        key=app.secret_key.encode(),
        msg=payload,
        digestmod=hashlib.sha256
    ).digest()
    
    # Constant-time comparison prevents timing oracles
    return hmac.compare_digest(computed_hash, expected_hash)

For Flask-RESTful APIs handling encrypted authentication tokens, implement a secure decorator:

from functools import wraps
from flask import request, g

def secure_decryption_required():
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            encrypted_token = request.headers.get('X-Encrypted-Token')
            
            if not encrypted_token:
                return jsonify({'error': 'Missing token'}), 401
            
            try:
                # Use OAEP padding and constant-time validation
                decrypted = private_key.decrypt(
                    bytes.fromhex(encrypted_token),
                    OAEP(
                        mgf=MGF1(algorithm=hashes.SHA256()),
                        algorithm=hashes.SHA256(),
                        label=None
                    )
                )
                
                # Store decrypted data in Flask's global context
                g.decrypted_token = decrypted
                
                return f(*args, **kwargs)
                
            except Exception:
                # Generic failure - no oracle information
                return jsonify({'error': 'Invalid token'}), 401
        
        return decorated_function
    return decorator

Finally, integrate middleBrick's CLI into your Flask development workflow to catch these issues early:

# Scan your Flask API before deployment
middlebrick scan http://localhost:5000/api/

# Integrate into your CI/CD pipeline
middlebrick scan --fail-below B /path/to/flask/app

These remediation steps eliminate the timing oracle and padding oracle vulnerabilities that make Bleichenbacher attacks possible in Flask applications, while maintaining the functionality your API requires.

Frequently Asked Questions

Why is PKCS#1 v1.5 padding vulnerable in Flask applications?
PKCS#1 v1.5 padding is vulnerable because it doesn't use constant-time operations during decryption. In Flask applications, this creates timing differences between various failure modes—such as incorrect padding format versus invalid padding bytes. Attackers can exploit these timing variations to gradually recover plaintext through thousands of carefully crafted requests. Additionally, Flask's default error handling often returns different HTTP status codes or error messages based on the type of decryption failure, providing an oracle without requiring timing analysis.
How does middleBrick detect Bleichenbacher vulnerabilities in my Flask API?
middleBrick detects Bleichenbacher vulnerabilities through multiple analysis layers. It performs static code analysis to identify use of PKCS#1 v1.5 padding, examines error handling patterns for oracle leakage, and actively probes your Flask endpoints by sending crafted ciphertexts. The scanner measures response time variations, HTTP status code differences, and JSON field variations that could indicate padding validation states. For Flask applications specifically, middleBrick also checks Flask-Session implementations and any custom middleware handling encrypted data, providing detailed reports with exact code locations and Flask-specific remediation guidance.