Cloudanix VulnDB

CVE-2016-9014

High · 8.1

CVSS

8.1

EPSS

6.1%

Published

Dec 9, 2016

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

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.

Chainable
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

  1. Attacker identifies a public Django application with `DEBUG = True`.
  2. Attacker configures a malicious DNS server for a domain they control, setting a low TTL.
  3. The DNS record initially points to an attacker-controlled IP address.
  4. A user is lured to a page on the attacker's domain, which loads malicious JavaScript.
  5. The attacker's DNS server updates the domain to resolve to an internal IP (e.g., 127.0.0.1).
  6. The malicious JavaScript makes a request to the original domain, which the browser now sends to the internal IP.
  7. 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