Open Redirect in Flask with Dynamodb
Open Redirect in Flask with Dynamodb — how this specific combination creates or exposes the vulnerability
An open redirect in a Flask application that uses DynamoDB for user or configuration data occurs when an attacker can control a redirect target derived from DynamoDB-stored values or request parameters that ultimately influence Flask's redirect behavior. In this combination, the vulnerability typically arises when a route reads a key (for example, a page slug or campaign identifier) from a DynamoDB item and then uses that value to construct a redirect URL without strict validation or allowlisting.
Consider a Flask route that fetches a redirect URL from a DynamoDB table based on a user-supplied ref parameter. If the application trusts the stored value and passes it directly to flask.redirect, an attacker who can inject or modify the DynamoDB item can cause the application to redirect users to malicious sites. This often maps to the Open Redirect entry in the OWASP API Security Top 10 and can be surfaced by middleBrick as a finding under Property Authorization or Input Validation checks.
DynamoDB itself does not perform URL validation; it stores whatever you put in. If your Flask app stores a destination URL in a DynamoDB attribute and later uses it without strict validation, the stored data becomes a persistence mechanism for the redirect payload. middleBrick’s checks for BOLA/IDOR and Property Authorization help detect cases where an attacker can manipulate identifiers to access or influence items that affect redirects.
Real-world impact: users are redirected to phishing or malware distribution pages, and the trust in your domain is abused. Because the scan is unauthenticated, middleBrick can exercise known patterns that reference redirect parameters and inspect whether responses perform redirects to external domains without proper constraints.
Dynamodb-Specific Remediation in Flask — concrete code fixes
Remediation centers on never trusting data stored in or retrieved from DynamoDB for redirect targets. Always validate and prefer allowlists. Below are concrete, safe patterns for Flask with DynamoDB using the AWS SDK for Python (boto3).
1. Validate and do not use raw stored URLs for redirects
Instead of storing full redirect URLs in DynamoDB, store only keys or slugs and map them to fixed, internal endpoints in your code.
import boto3
from flask import Flask, request, redirect, abort
app = Flask(__name__)
ddb = boto3.resource('dynamodb', region_name='us-east-1')
table = ddb.Table('redirects')
# Safe: map a key to an internal path; do not use raw external URLs from DynamoDB
ALLOWED_TARGETS = {
'dashboard': '/app/dashboard',
'settings': '/app/settings',
'help': '/app/help'
}
@app.route('/go')
def go():
key = request.args.get('key')
if not key:
abort(400, 'missing key')
item = table.get_item(Key={'key': key}).get('Item')
if not item:
abort(404)
# Do not use item['external_url'] for redirect; use a controlled mapping
target = ALLOWED_TARGETS.get(item.get('route_key'))
if not target:
abort(400, 'invalid route key')
return redirect(target, code=302)
2. If you must store URLs, enforce strict allowlisting and normalization
When you must store URLs, validate against a strict allowlist of domains and ensure the URL is well-formed. Do not allow schemeless or javascript: URLs.
from urllib.parse import urlparse
import boto3
from flask import Flask, request, redirect, abort
app = Flask(__name__)
ddb = boto3.resource('dynamodb', region_name='us-east-1')
table = ddb.Table('redirects')
ALLOWED_DOMAINS = {'app.example.com', 'static.example.com'}
def is_safe_url(url: str) -> bool:
parsed = urlparse(url)
if parsed.scheme not in ('https',):
return False
if parsed.netloc not in ALLOWED_DOMAINS:
return False
# Reject javascript: and other unsafe schemes already handled by parse
return True
@app.route('/external')
def external():
key = request.args.get('key')
item = table.get_item(Key={'key': key}).get('Item')
if not item:
abort(404)
raw = item.get('url')
if not raw or not is_safe_url(raw):
abort(400, 'invalid redirect target')
return redirect(raw, code=302)
3. Use signed tokens for indirect references instead of raw identifiers
Generate short-lived signed tokens on the server that reference an internal ID. Verify the token on redirect to ensure the request is legitimate and cannot be tampered with via DynamoDB manipulation.
import boto3
from flask import Flask, request, redirect, abort
import itsdangerous
app = Flask(__name__)
app.config['SECRET_KEY'] = 'change-this-to-a-secure-random-key'
signer = itsdangerous.TimestampSigner(app.config['SECRET_KEY'])
ddb = boto3.resource('dynamodb', region_name='us-east-1')
table = ddb.Table('redirects')
@app.route('/redirect')
def redirect_route():
token = request.args.get('token')
try:
internal_id = signer.unsign_token(token, max_age=300) # 5 minutes
except itsdangerous.BadSignature:
abort(400, 'invalid token')
item = table.get_item(Key={'id': internal_id}).get('Item')
if not item or 'safe_path' not in item:
abort(404)
# Use a controlled path; do not follow external_url from DynamoDB
return redirect(item['safe_path'], code=302)
These patterns ensure that DynamoDB-stored data never directly dictates the redirect target. middleBrick’s checks for Input Validation, Property Authorization, and BOLA/IDOR are valuable for detecting configurations where stored data may influence client navigation without proper constraints.