CVE-2011-4138
NoneCVSS
—
EPSS
2.4%
Published
Oct 19, 2011
CISA due date
—
Cloudanix analysis
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.
- 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
- Attacker identifies a Django application using a URLField with the `verify_exists` option enabled.
- Attacker hosts a malicious web service that responds to HEAD requests with an HTTP redirect.
- Attacker submits the URL of their malicious service to the vulnerable Django application.
- The Django server sends a HEAD request to the attacker's URL.
- The attacker's service replies with a 302 redirect to a chosen internal URL.
- The Django server makes a GET request to the internal URL, effectively acting as a proxy for the attacker.
- 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
- GHSA-8p8v-wh79-9r56 Django vulnerable to Uncontrolled Resource Consumption Also affects django
- GHSA-mjgh-79qc-68w3 Django has a Race Condition vulnerability Also affects django
- CVE-2026-25673 An issue was discovered in 6.0 before 6.0.3, 5.2 before 5.2.12, and 4.2 before 4.2.29. Also affects django
- CVE-2026-25674 An issue was discovered in 6.0 before 6.0.3, 5.2 before 5.2.12, and 4.2 before 4.2.29. Also affects django
- GHSA-6426-9fv3-65x8 Django has an SQL Injection issue Also affects django
- GHSA-gvg8-93h5-g6qq Django has an SQL Injection issue Also affects django
- GHSA-2mcm-79hx-8fxw Django has Observable Timing Discrepancy Also affects django
- GHSA-33mw-q7rj-mjwj Django has Inefficient Algorithmic Complexity Also affects django