CVE-2016-9014
High · 8.1CVSS
8.1
EPSS
6.1%
Published
Dec 9, 2016
CISA due date
—
Cloudanix analysis
A serious misconfiguration in the web application framework could allow an attacker to bypass firewall protections and access internal services if the application is accidentally left in "debug mode" in a live environment.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- High
- Impact
- Full Compromise
- Component
- Web Framework
- Class
- SSRF
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
When Django is run with `settings.DEBUG = True`, it fails to validate the HTTP Host header against the `ALLOWED_HOSTS` list. This allows an attacker to perform DNS rebinding attacks. By manipulating DNS responses, an attacker can trick a user's browser into sending requests to internal IP addresses (e.g., 127.0.0.1) while bypassing the browser's same-origin policy. This effectively enables an attacker to scan and interact with services running on the local machine or internal network that are accessible from the Django server, leading to information disclosure or further compromise.
Why it matters to the business
Running a web application in 'debug mode' in a live environment is a critical misconfiguration that effectively disables key security controls. This vulnerability allows attackers to bypass firewall rules and access internal, non-public network services. A successful exploit could lead to a significant data breach, compromise of internal infrastructure, or service disruption. The primary business risk stems from deploying development configurations into production, which can expose sensitive data and systems directly to the internet.
How an attack unfolds
An attacker first identifies a public Django application running with `DEBUG = True`. The attacker then sets up a malicious domain with a DNS record that has a very short Time-To-Live (TTL). Initially, this domain points to an attacker-controlled server. The attacker tricks a victim into visiting a page on this domain. This page contains JavaScript that makes subsequent requests back to the same domain. In between these requests, the attacker updates the DNS record to point to an internal IP address, such as `127.0.0.1`. The victim's browser, honoring the short TTL, re-resolves the domain to the new internal IP. It then sends the request to the internal service, but the request still contains the original `Host` header of the attacker's domain. Because the vulnerable Django application is in debug mode, it doesn't validate this `Host` header, allowing the attacker's script to interact with and exploit internal services as if it were on the local network.
How to fix it
The most critical remediation step is to ensure `settings.DEBUG` is set to `False` in all production environments. This setting should never be enabled outside of local development. Additionally, configure the `ALLOWED_HOSTS` setting in `settings.py` with a specific whitelist of the domains that are permitted to serve the application. As a best practice, upgrade Django to a patched version: 1.8.16 or later for the 1.8.x series, 1.9.11 or later for the 1.9.x series, or 1.10.3 or later for the 1.10.x series. All versions from Django 1.11 onward also contain the fix.
How to confirm the fix worked
To confirm remediation, inspect the application's configuration files (e.g., `settings.py`) in all production and staging environments to verify that `settings.DEBUG` is set to `False`. Also, ensure the `ALLOWED_HOSTS` list is not empty and contains only the expected hostnames. You can test the configuration by sending a request to the application's IP address with an arbitrary `Host` header, like `curl -H "Host: evil.com" http://<your_app_ip>`. A properly configured server should reject this request with an HTTP 400 Bad Request error.
Typical attack path
- Attacker identifies a public Django application with `DEBUG = True`.
- Attacker configures a malicious DNS server for a domain they control, setting a low TTL.
- The DNS record initially points to an attacker-controlled IP address.
- A user is lured to a page on the attacker's domain, which loads malicious JavaScript.
- The attacker's DNS server updates the domain to resolve to an internal IP (e.g., 127.0.0.1).
- The malicious JavaScript makes a request to the original domain, which the browser now sends to the internal IP.
- The vulnerable Django application receives the request with a mismatched Host header and processes it, allowing interaction with the internal service.
How to detect it
To detect potential exploitation, security teams should analyze web server access logs for requests where the HTTP `Host` header does not match the server's legitimate domain name. The presence of Django's detailed debug error pages being served to external IP addresses is a strong indicator of the prerequisite misconfiguration. Monitoring for this behavior can help identify vulnerable instances. Correlating logs from web servers and DNS servers may reveal suspicious DNS rebinding activity, although this is challenging. Focus on identifying requests with unexpected `Host` headers that result in successful (HTTP 200) responses for internal resources.
- You're seeing this error because you have DEBUG = True in your Django settings file.
What your security team should do
- Immediately audit all deployed Django applications to ensure `settings.DEBUG` is set to `False` in production. This is the highest priority action.
- Enforce a policy that all Django projects must have a properly configured `ALLOWED_HOSTS` setting before deployment.
- Upgrade all Django instances to a patched version (e.g., 1.10.3+) or a modern, supported release to benefit from this and other security fixes.
- Incorporate automated checks into CI/CD pipelines to prevent code with `DEBUG = True` from being deployed to production.
The record
Django before 1.8.x before 1.8.16, 1.9.x before 1.9.11, and 1.10.x before 1.10.3, when settings.DEBUG is True, allow remote attackers to conduct DNS rebinding attacks by leveraging failure to validate the HTTP Host header against settings.ALLOWED_HOSTS.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| PyPI | django | 0 | 1.8.16 |
| PyPI | django | 1.10 | 1.10.3 |
| PyPI | django | 1.10a1 | 1.10.3 |
| PyPI | django | 1.8 | 1.8.16 |
| PyPI | django | 1.8a1 | 1.8.16 |
| PyPI | django | 1.9 | 1.9.11 |
| PyPI | django | 1.9a1 | 1.9.11 |
| Alpine:v3.10 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.11 | py3-django | 0 | 1.8.16-r0 |
| Alpine:v3.12 | py3-django | 0 | 1.8.16-r0 |
| Alpine:v3.2 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.3 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.4 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.5 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.6 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.7 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.8 | py-django | 0 | 1.8.16-r0 |
| Alpine:v3.9 | py-django | 0 | 1.8.16-r0 |
| Debian:11 | python-django | 0 | 1:1.10.3-1 |
| Debian:12 | python-django | 0 | 1:1.10.3-1 |
| Debian:13 | python-django | 0 | 1:1.10.3-1 |
| Debian:14 | python-django | 0 | 1:1.10.3-1 |
| Debian:7 | python-django | 0 | 1.4.22-1+deb7u2 |
| Debian:8 | python-django | 0 | 1.7.11-1+deb8u2 |
| Mageia:5 | python-django | 0 | 1.8.16-1.mga5 |
| SUSE:OpenStack Cloud 6 | python-Django | 0 | 1.8.19-3.6.1 |
| SUSE:OpenStack Cloud 7 | python-Django | 0 | 1.8.19-3.4.1 |
| Ubuntu:14.04:LTS | python-django | 0 | 1.6.1-2ubuntu0.16 |
| Ubuntu:16.04:LTS | python-django | 0 | 1.8.7-1ubuntu5.4 |
| pypi | Django | 1.10a1 | No fix |
| pypi | Django | 1.8a1 | No fix |
| pypi | Django | 1.9a1 | 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