HIGH ssrf server sidedjangopython

Ssrf Server Side in Django (Python)

Ssrf Server Side in Django with Python — how this specific combination creates or exposes the vulnerability

Server Side Request Forgery (SSRF) in Django with Python arises when an application accepts a URL from an attacker and uses Python libraries to make HTTP requests without adequate validation or network controls. Django views written in Python often use requests or urllib to call external services, and if the target URL is user-supplied, an attacker can coerce the server to interact with internal endpoints, cloud metadata services, or restricted ports.

In a typical Django app, a vulnerable pattern looks like this: a client provides a URL via a query parameter or JSON body, and the backend passes it directly to requests.get. Because Python’s standard library and third-party packages resolve redirects and support diverse schemes (including file://, http://, and sometimes custom schemes), an attacker can reach internal services that are not exposed on the public internet. SSRF can also occur when Django is deployed in cloud environments; the Python process may have access to instance metadata at 169.254.169.254, and an SSRF vulnerability can expose metadata tokens, internal IPs, or sensitive cloud resources.

The Django framework itself does not introduce the vulnerability; the risk comes from how Python code handles untrusted input. For example, if a developer uses urllib.request.urlopen with a user-controlled host and port, the server can be tricked into scanning internal networks or connecting to malicious reverse proxies. Python’s flexible URL handling and the wide ecosystem of HTTP libraries mean that SSRF often requires careful review of deserialization, redirects, and URL parsing logic. Attack patterns such as internal port probing, metadata exfiltration, and interaction with cloud instance metadata are common when SSRF exists in a Django + Python stack.

Python-Specific Remediation in Django — concrete code fixes

To remediate SSRF in Django with Python, validate and restrict outbound destinations at the code level. Prefer an allowlist of domains and ports, avoid forwarding user input directly to network calls, and disable unnecessary URL schemes. Below are concrete, safe patterns.

1. Use an allowlist and urllib.parse to validate the URL

from urllib.parse import urlparse
from django.http import JsonResponse
import requests

def safe_external_fetch(request):
    target = request.GET.get('url', '')
    parsed = urlparse(target)
    # Allowlist only specific domains and schemes
    if parsed.scheme not in ('https',):
        return JsonResponse({'error': 'Unsupported scheme'}, status=400)
    if parsed.hostname not in ('api.example.com', 'data.example.org'):
        return JsonResponse({'error': 'Host not allowed'}, status=403)
    # Enforce HTTPS and an optional port
    if parsed.port and parsed.port != 443:
        return JsonResponse({'error': 'Port not allowed'}, status=403)
    resp = requests.get(target, timeout=5, allow_redirects=False)
    return JsonResponse({'status': resp.status_code})

2. Avoid passing user input to remote calls; use an internal mapping

from django.http import JsonResponse
import requests

SERVICE_MAP = {
    'users': 'https://api.example.com/v1/users',
    'products': 'https://api.example.com/v1/products',
}

def fetch_mapped_service(request):
    key = request.GET.get('service')
    if key not in SERVICE_MAP:
        return JsonResponse({'error': 'Invalid service'}, status=400)
    url = SERVICE_MAP[key]
    # Optional: add per-service headers, auth, or query params safely
    resp = requests.get(url, timeout=5)
    return JsonResponse({'data': resp.json()})

3. Use requests with explicit parameters and disable redirects

import requests
from django.http import HttpResponseBadRequest

def limited_fetch(url: str):
    # Reject URLs with non-HTTPS schemes
    if not url.lower().startswith('https://'):
        raise ValueError('Only HTTPS allowed')
    try:
        response = requests.get(
            url,
            timeout=5,
            allow_redirects=False,
            headers={'User-Agent': 'middleBrick educational scanner'},
        )
        response.raise_for_status()
        return response.text
    except requests.RequestException as e:
        return f'Error: {e}'

4. Harden against SSRF in deployment

  • Run Django workers in network segments that deny outbound connections to sensitive internal endpoints (e.g., metadata service).
  • Use firewall rules or service mesh policies to restrict egress from the application container.
  • Apply principle of least privilege to the runtime identity used by the Python process.

middleBrick can support secure development workflows by integrating scans into your CI/CD pipeline; for example, the GitHub Action can fail builds if risk scores degrade, while the CLI provides JSON output for scripting. The Dashboard helps track API security scores over time, and the MCP Server lets you scan APIs directly from your AI coding assistant.

Frequently Asked Questions

Can SSRF in Django expose cloud metadata even if the app uses only external APIs?
Yes. If the Django app runs in a cloud environment and the Python process can reach the instance metadata service, an SSRF vulnerability can allow attackers to harvest tokens or internal data, regardless of whether your code primarily calls external APIs.
Is simply upgrading Python or Django enough to prevent SSRF?
No. SSRF is an application-level issue stemming from how URLs are accepted and used. Upgrading Python or Django does not remove the risk; you must validate inputs, restrict schemes and hosts, and limit outbound network paths.