SSRF

SSRF in Flask: remediation guide [Apr 2026] [GHSA-x6m9-gxvr-7jpv]

[Updated Apr 2026] Updated GHSA-x6m9-gxvr-7jpv

Overview

Server-Side Request Forgery (SSRF) vulnerabilities allow an attacker to cause the server to make HTTP requests on their behalf. In Flask apps that expose endpoints which fetch external resources using user-supplied URLs, an attacker can reach internal services, cloud metadata endpoints, or other protected resources. This can lead to data exposure, exfiltration, lateral movement, or access to sensitive internal networks. The impact scales with the trust level of the Flask process and the surrounding network permissions, potentially enabling sensitive information disclosure or unauthorized actions from within a trusted network.

Code Fix Example

Flask API Security Remediation
# Vulnerable pattern (FFLASK SSRF risk)\nfrom flask import Flask, request, Response\nimport requests\n\napp = Flask(__name__)\n\[email protected]("/proxy")\ndef proxy_vulnerable():\n    target = request.args.get('url')\n    resp = requests.get(target, timeout=5)\n    return Response(resp.content, status=resp.status_code, content_type=resp.headers.get('Content-Type', 'text/plain'))\n\n# ------------------------------------------------------------------\n# Fixed pattern (SSRF protected via allowlist and validation)\nimport urllib.parse\nimport ipaddress\n\nALLOWED_HOSTNAMES = {"example.com", "assets.example.com"}  # replace with your safe domains\n\ndef is_allowed(url: str) -> bool:\n    if not url:\n        return False\n    try:\n        parsed = urllib.parse.urlparse(url)\n    except Exception:\n        return False\n    if parsed.scheme not in {"http", "https"}:\n        return False\n    host = parsed.hostname\n    if not host:\n        return False\n    # Disallow private and loopback addresses when possible\n    try:\n        ip = ipaddress.ip_address(host)\n        if ip.is_private or ip.is_loopback:\n            return False\n    except ValueError:\n        pass  # host is not an IP, continue with hostname checks\n    for allowed in ALLOWED_HOSTNAMES:\n        if host == allowed or host.endswith("." + allowed):\n            return True\n    return False\n\napp = Flask(__name__)\n\[email protected]("/proxy-secure")\ndef proxy_secure():\n    target = request.args.get('url')\n    if not is_allowed(target):\n        return "Forbidden", 403\n    resp = requests.get(target, timeout=5, allow_redirects=False, verify=True)\n    return Response(resp.content, status=resp.status_code, content_type=resp.headers.get('Content-Type', 'text/plain'))

CVE References

Choose which optional cookies to allow. You can change this any time.