Ssrf in Flask with Dynamodb
Ssrf in Flask with Dynamodb — how this specific combination creates or exposes the vulnerability
Server-Side Request Forgery (SSRF) in a Flask application that interacts with Amazon DynamoDB typically arises when the application constructs HTTP requests to external services using data supplied by the caller. An attacker can supply a malicious URL or metadata service endpoint that the server-side code uses to build a request, causing the backend to perform unintended network actions. Because DynamoDB access patterns often involve SDK calls that may rely on HTTP clients, SSRF can indirectly affect DynamoDB operations if the attacker influences endpoint resolution, credential retrieval, or metadata queries.
Flask applications may expose SSRRF when they accept user input such as a table name, key condition expression, or a URL for importing external data and pass it to DynamoDB utilities without strict validation. For example, if the application fetches an external schema or mapping from a user-provided URL and uses that to shape DynamoDB requests, an attacker can point the request to the instance metadata service (169.254.169.254) to obtain sensitive IAM credentials or to probe internal services. Similarly, a misconfigured HTTP client used by the DynamoDB wrapper can be redirected to internal endpoints due to hostname confusion or lack of URL validation.
The risk is compounded when the application uses the AWS SDK for JavaScript (v3) or boto3 with custom HTTP agents or proxy configurations that do not enforce strict endpoint whitelisting. An SSRF vector may not directly mutate DynamoDB data, but it can reveal sensitive information about the runtime environment used to access DynamoDB, such as IAM role credentials attached to the host. This can lead to privilege escalation if the compromised credentials have broad DynamoDB permissions. Therefore, validating and sanitizing any user-influenced inputs that affect network destinations is crucial in Flask-DynamoDB integrations.
Dynamodb-Specific Remediation in Flask — concrete code fixes
To mitigate SSRF in a Flask application working with DynamoDB, enforce strict allowlisting of endpoints and avoid using user input to construct network destinations. When using the AWS SDK for JavaScript (v3), configure the DynamoDB client with a custom HTTPS agent that restricts resolved hostnames. For boto3, avoid passing user-controlled host headers and use resource endpoints that are hardcoded or selected from a safe set.
Example: Safe DynamoDB client configuration in Flask (AWS SDK v3)
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
import https from "https";
const agent = new https.Agent({
rejectUnauthorized: true,
});
const client = new DynamoDBClient({
region: "us-east-1",
requestHandler: {
httpsAgent: agent,
},
credentials: fromNodeProviderChain(),
});
export default client;
Example: Safe DynamoDB access in Flask routes
from flask import Flask, request, jsonify
import boto3
from botocore.exceptions import ClientError
app = Flask(__name__)
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
@app.route('/tables//items', methods=['GET'])
def get_items(table_name):
# Strict allowlist for table names
allowed_tables = {'users', 'products', 'orders'}
if table_name not in allowed_tables:
return jsonify({'error': 'invalid table'}), 400
table = dynamodb.Table(table_name)
try:
response = table.scan()
return jsonify(response.get('Items', []))
except ClientError as e:
return jsonify({'error': str(e)}), 500
Example: Validating external URLs when used with DynamoDB workflows
from flask import Flask, request, jsonify
from urllib.parse import urlparse
import requests
app = Flask(__name__)
def is_safe_url(url):
parsed = urlparse(url)
return parsed.scheme in ('https',) and parsed.hostname in ('example.com', 'api.example.com')
@app.route('/import', methods=['POST'])
def import_metadata():
data = request.get_json()
external_url = data.get('url')
if not is_safe_url(external_url):
return jsonify({'error': 'invalid url'}), 400
resp = requests.get(external_url, timeout=5)
resp.raise_for_status()
# Use resp.json() to shape DynamoDB put_item calls safely
return jsonify({'status': 'ok'})
Additional SSRF mitigations
- Disable redirect following or validate each redirect target against an allowlist.
- Run the Flask application with minimal IAM permissions so that even if SSRF occurs, the attacker cannot perform destructive DynamoDB operations.
- Use VPC endpoints for DynamoDB to keep traffic within the AWS network and reduce exposure to external SSRF-induced data leaks.
Related CWEs: ssrf
| CWE ID | Name | Severity |
|---|---|---|
| CWE-918 | Server-Side Request Forgery (SSRF) | CRITICAL |
| CWE-441 | Unintended Proxy or Intermediary (Confused Deputy) | HIGH |
Frequently Asked Questions
How can I validate DynamoDB table names safely in Flask?
if table_name in {'users', 'products', 'orders'}: before accessing dynamodb.Table(table_name).