HIGH open redirectflaskapi keys

Open Redirect in Flask with Api Keys

Open Redirect in Flask with Api Keys — how this specific combination creates or exposes the vulnerability

An open redirect in a Flask application that uses API keys occurs when an endpoint accepts a user-supplied URL or redirect target and incorporates an API key in the flow without proper validation. For example, a common pattern is a callback or OAuth redirect where the client provides a next or redirect_uri parameter, and the server uses an API key to authenticate outgoing requests or to sign a redirect token. If the API key is embedded in the redirect response (e.g., as a query parameter or in a Location header) and the target URL is not strictly validated, an attacker can supply a malicious host, causing the application to redirect authenticated users or leak the key in Referer headers.

Consider a Flask route that accepts a redirect URL and an API key for downstream service authorization:

from flask import Flask, request, redirect, url_for, make_response

app = Flask(__name__)

@app.route('/callback')
def callback():
    api_key = request.args.get('api_key')
    redirect_to = request.args.get('next', '/')  # user-controlled
    # Danger: using the API key in a redirect or token that includes user input
    token = f'key={api_key}'
    return redirect(f'{redirect_to}?token={token}')

In this pattern, if redirect_to is not validated, an attacker can set next to a malicious domain (e.g., https://evil.com/?code=stolen). The API key may be exposed in the Referer header when the browser follows the redirect, or the application may be tricked into issuing a signed token or OAuth state that points to an attacker-controlled host. This violates the same-origin principle and can lead to phishing or session fixation, especially when the API key is used to authorize downstream calls that are chained to the redirect.

Another scenario involves API-key-gated admin endpoints that perform server-side redirects to third-party services (e.g., payment gateways). If the service URL is built from user input and the API key is logged or echoed in error messages, an attacker can craft a redirect that causes the server to follow an unintended path, potentially exfiltrating the key via logs or SSRF-adjacent behaviors. Because the API key is treated as a credential, exposing it through an open redirect significantly increases the impact, as the key can be reused across requests.

Api Keys-Specific Remediation in Flask — concrete code fixes

To remediate open redirect risks when API keys are involved, treat the API key as a sensitive credential that must never be exposed in redirects or URLs. Always validate and normalize redirect targets against an allowlist, and avoid echoing API keys in responses, headers, or logs. Below are concrete, secure patterns for Flask.

1. Validate redirect targets against an allowlist

Only permit redirects to known, trusted paths or domains. Do not rely on hostname checks alone; use URL parsing to enforce strict path and scheme rules.

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

app = Flask(__name__)

ALLOWED_REDIRECT_HOSTS = {'app.example.com', 'cdn.example.com'}

def is_safe_url(target):
    ref = request.host_url
    try:
        parsed = urlparse(target)
        if parsed.scheme not in {'http', 'https'}:
            return False
        # Ensure the target is relative or matches allowed hosts
        if parsed.netloc and parsed.netloc not in ALLOWED_REDIRECT_HOSTS:
            return False
        # Use url_join to resolve relative URLs safely
        safe_target = urljoin(request.host_url, target)
        return safe_target.startswith(request.host_url)
    except Exception:
        return False

@app.route('/login')
def login():
    api_key = request.args.get('api_key')
    # Do NOT use api_key in redirect construction
    next_url = request.args.get('next', '/')
    if not is_safe_url(next_url):
        next_url = '/'
    # Store api_key securely server-side (e.g., session) rather than in redirect
    return redirect(next_url)

2. Avoid embedding API keys in redirects or tokens

Never place API keys in query parameters, headers, or body of a redirect response. If a token is required for the client, generate a short-lived, server-side session or use signed cookies instead.

from flask import Flask, request, redirect, make_response
import secrets

app = Flask(__name__)

@app.route('/auth-callback')
def auth_callback():
    api_key = request.args.get('api_key')
    redirect_to = request.args.get('next', '/')
    if not is_safe_url(redirect_to):
        redirect_to = '/'
    # Do not concatenate API key into redirect URL
    session_id = secrets.token_urlsafe(16)
    # Store mapping server-side (e.g., in memory cache) with limited TTL
    # server_side_store[session_id] = api_key  # managed securely
    response = make_response(redirect(redirect_to))
    response.set_cookie('session_id', session_id, httponly=True, samesite='Lax', secure=True)
    return response

3. Sanitize inputs and use framework utilities

Always treat user input as untrusted. Use Werkzeug’s utilities to validate URLs and prefer relative paths. Log suspicious redirect attempts without exposing keys.

from werkzeug.urls import url_parse

@app.before_request
def validate_redirect_params():
    if request.path == '/auth-callback':
        next_url = request.args.get('next', '')
        if next_url:
            parsed = url_parse(next_url)
            if parsed.host and parsed.host != request.host.split(':')[0]:
                # Reject or sanitize
                raise ValueError('Invalid redirect target')

Frequently Asked Questions

Why is embedding an API key in a redirect URL dangerous?
Embedding an API key in a redirect URL can expose the key via Referer headers, browser history, or logs. It also enables phishing or open redirect attacks where attackers trick users into visiting malicious domains that receive the key.
How can I safely handle redirects in Flask when API keys are involved?
Validate redirect targets against an allowlist, avoid including API keys in URLs, store keys server-side (e.g., session cache), and use short-lived tokens or signed cookies instead of raw API keys in client-side flows.