Cloudanix VulnDB

CVE-2011-4138

None

CVSS

—

EPSS

2.4%

Published

Oct 19, 2011

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A flaw in the web application framework can be exploited by an attacker to force the server to access internal network systems, potentially leading to a data breach.

Chainable
Exploitation
Remote Unauthenticated
Attacker needs
None
Complexity
Low
Impact
Other
Component
Web Framework
Class
Improper Input Validation
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

The vulnerability is a Server-Side Request Forgery (SSRF) in Django's URLField component. When the `verify_exists` option is enabled, the field validator sends a HEAD request to a user-supplied URL. If it receives an HTTP redirect, it insecurely follows the redirect by sending a GET request to the new URL. This allows a remote attacker to force the server to send arbitrary GET requests to any URL, including internal network resources that are not directly accessible from the internet. This can be used to scan internal networks, interact with internal services, and exfiltrate data from those services.

Why it matters to the business

An attacker can abuse this flaw to make the application server act as a proxy, bypassing firewall rules and accessing sensitive internal network services. This could lead to the exposure of confidential data, reconnaissance of the internal corporate network, or disruption of internal business applications. Since the malicious requests originate from a trusted server, they are more likely to succeed and less likely to be detected by standard network security monitoring.

How an attack unfolds

An attacker identifies a web application using a vulnerable version of Django that accepts user-supplied URLs in a form with a URLField validator. The attacker sets up their own web server. They then submit a URL pointing to their server to the vulnerable application. When the Django server attempts to validate this URL, it sends a HEAD request to the attacker's server. The attacker's server responds with an HTTP 3xx redirect, providing a `Location` header that points to a sensitive internal endpoint (e.g., `http://10.0.0.1/admin` or a cloud metadata service like `http://169.254.169.254/latest/meta-data`). The vulnerable Django server follows this redirect by making a GET request to the internal URL. The response from this internal service may then be leaked to the attacker, for instance, through error messages or other application behavior.

How to fix it

Upgrade Django to a patched version. For applications running Django 1.2.x, upgrade to version 1.2.7 or later. For applications running Django 1.3.x, upgrade to version 1.3.1 or later. If an immediate upgrade is not possible, a temporary mitigation is to disable the vulnerable functionality by setting `verify_exists=False` on all URLField instances in the application's forms and models. Additionally, implement strict egress network filtering to prevent the application server from making unauthorized connections to internal IP ranges and cloud metadata services.

How to confirm the fix worked

To validate the patch, check the installed Django version by running `python -m django --version` and ensure it is 1.2.7+ or 1.3.1+. To test for the vulnerability, create a form with a URLField set to `verify_exists=True`. Set up a web server that responds to HEAD requests with a 302 redirect to an internal-only service. Submit the URL of this test server to the form. On a vulnerable system, network monitoring will show the server attempting a GET request to the internal service. On a patched system, this GET request will not be made.

Typical attack path

  1. Attacker identifies a Django application using a URLField with the `verify_exists` option enabled.
  2. Attacker hosts a malicious web service that responds to HEAD requests with an HTTP redirect.
  3. Attacker submits the URL of their malicious service to the vulnerable Django application.
  4. The Django server sends a HEAD request to the attacker's URL.
  5. The attacker's service replies with a 302 redirect to a chosen internal URL.
  6. The Django server makes a GET request to the internal URL, effectively acting as a proxy for the attacker.
  7. The attacker infers the content of the internal resource from the application's subsequent response or behavior.

How to detect it

Monitor network traffic originating from Django application servers. Look for suspicious outbound GET requests, especially those directed at internal IP address ranges (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), localhost (127.0.0.1), and cloud provider metadata services (169.254.169.254). Correlate these outbound requests with recent inbound requests to the application. On internal services, check web server access logs for unexpected requests where the source IP is a Django application server and the User-Agent may be a default Python library like `Python-urllib/2.7`.

  • Outbound network connection from Django server to 169.254.169.254
  • Outbound network connection from Django server to an IP in 10.0.0.0/8
  • Outbound network connection from Django server to an IP in 172.16.0.0/12
  • Outbound network connection from Django server to an IP in 192.168.0.0/16
  • In internal service logs, an HTTP request with User-Agent: Python-urllib/2.6
  • In internal service logs, an HTTP request with User-Agent: Python-urllib/2.7

What your security team should do

  • Immediately identify all applications using vulnerable Django versions and prioritize upgrading them to 1.2.7+ or 1.3.1+.
  • If patching is delayed, audit application code for `URLField(verify_exists=True)` and disable this option as a short-term mitigation.
  • Enforce strict egress filtering rules on all application servers to block outbound requests to internal IP ranges (RFC1918) and cloud metadata endpoints (169.254.169.254).
  • Use dynamic application security testing (DAST) tools to scan for SSRF vulnerabilities in all web-facing applications.

The record

The verify_exists functionality in the URLField implementation in Django before 1.2.7 and 1.3.x before 1.3.1 originally tests a URL's validity through a HEAD request, but then uses a GET request for the new target URL in the case of a redirect, which might allow remote attackers to trigger arbitrary GET requests with an unintended source IP address via a crafted Location header.

Affected packages

Ecosystem Package Introduced Fixed
PyPI django 0 1.2.7
PyPI django 1.3 1.3.1
Debian:11 python-django 0 1.3.1-1
Debian:12 python-django 0 1.3.1-1
Debian:13 python-django 0 1.3.1-1
Debian:5.0 python-django 0 1.0.2-1+lenny3
Debian:6.0 python-django 0 1.2.3-3+squeeze2
pypi Django 1.3 No fix

Related vulnerabilities