VYPR
High severityNVD Advisory· Published Oct 19, 2011· Updated Apr 29, 2026

CVE-2011-4139

CVE-2011-4139

Description

Django before 1.2.7 and 1.3.x before 1.3.1 uses a request's HTTP Host header to construct a full URL in certain circumstances, which allows remote attackers to conduct cache poisoning attacks via a crafted request.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
DjangoPyPI
< 1.2.71.2.7
DjangoPyPI
>= 1.3, < 1.3.11.3.1

Affected products

22
  • cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*+ 21 more
    • cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*range: <=1.2.6
    • cpe:2.3:a:djangoproject:django:0.91:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.95:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.95.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.96:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1.3:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.1:2:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.3:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.4:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.5:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.3:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.3:alpha1:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.3:alpha2:*:*:*:*:*:*

Patches

2
c613af4d6485

[1.2.X] Added protection against spoofing of X_FORWARDED_HOST headers. A security announcement will be made shortly.

https://github.com/django/djangoRussell Keith-MageeSep 10, 2011via ghsa
5 files changed · +112 5
  • django/conf/global_settings.py+2 0 modified
    @@ -390,6 +390,8 @@
     DEFAULT_TABLESPACE = ''
     DEFAULT_INDEX_TABLESPACE = ''
     
    +USE_X_FORWARDED_HOST = False
    +
     ##############
     # MIDDLEWARE #
     ##############
    
  • django/http/__init__.py+2 1 modified
    @@ -45,7 +45,8 @@ def __repr__(self):
         def get_host(self):
             """Returns the HTTP host using the environment or request headers."""
             # We try three options, in order of decreasing preference.
    -        if 'HTTP_X_FORWARDED_HOST' in self.META:
    +        if settings.USE_X_FORWARDED_HOST and (
    +            'HTTP_X_FORWARDED_HOST' in self.META):
                 host = self.META['HTTP_X_FORWARDED_HOST']
             elif 'HTTP_HOST' in self.META:
                 host = self.META['HTTP_HOST']
    
  • docs/ref/request-response.txt+5 4 modified
    @@ -185,10 +185,11 @@ Methods
     
     .. method:: HttpRequest.get_host()
     
    -    Returns the originating host of the request using information from the
    -    ``HTTP_X_FORWARDED_HOST`` and ``HTTP_HOST`` headers (in that order). If
    -    they don't provide a value, the method uses a combination of
    -    ``SERVER_NAME`` and ``SERVER_PORT`` as detailed in `PEP 333`_.
    +    Returns the originating host of the request using information from
    +    the ``HTTP_X_FORWARDED_HOST`` (if enabled in the settings) and ``HTTP_HOST``
    +    headers (in that order). If they don't provide a value, the method
    +    uses a combination of ``SERVER_NAME`` and ``SERVER_PORT`` as
    +    detailed in :pep:`3333`.
     
         .. _PEP 333: http://www.python.org/dev/peps/pep-0333/
     
    
  • docs/ref/settings.txt+13 0 modified
    @@ -1698,6 +1698,19 @@ and ``NUMBER_GROUPING`` from current locale, to format the number.
     
     See also ``THOUSAND_SEPARATOR`` and ``NUMBER_GROUPING``.
     
    +.. setting:: USE_X_FORWARDED_HOST
    +
    +USE_X_FORWARDED_HOST
    +--------------------
    +
    +.. versionadded:: 1.3.1
    +
    +Default: ``False``
    +
    +A boolean that specifies whether to use the X-Forwarded-Host header in
    +preference to the Host header. This should only be enabled if a proxy
    +which sets this header is in use.
    +
     .. setting:: YEAR_MONTH_FORMAT
     
     YEAR_MONTH_FORMAT
    
  • tests/regressiontests/requests/tests.py+90 0 modified
    @@ -2,11 +2,13 @@
     import time
     import unittest
     
    +from django.conf import settings
     from django.http import HttpRequest, HttpResponse, parse_cookie
     from django.core.handlers.wsgi import WSGIRequest
     from django.core.handlers.modpython import ModPythonRequest
     from django.utils.http import cookie_date
     
    +
     class RequestsTests(unittest.TestCase):
     
         def test_httprequest(self):
    @@ -57,3 +59,91 @@ def test_httprequest_location(self):
             request.path = ''
             self.assertEqual(request.build_absolute_uri(location="/path/with:colons"),
                 'http://www.example.com/path/with:colons')
    +
    +    def test_http_get_host(self):
    +        old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
    +        try:
    +            settings.USE_X_FORWARDED_HOST = False
    +
    +            # Check if X_FORWARDED_HOST is provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_X_FORWARDED_HOST': u'forward.com',
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            # X_FORWARDED_HOST is ignored.
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if X_FORWARDED_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if HTTP_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com')
    +
    +            # Check if HTTP_HOST isn't provided, and we're on a nonstandard port
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 8042,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com:8042')
    +
    +        finally:
    +            settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
    +
    +    def test_http_get_host_with_x_forwarded_host(self):
    +        old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
    +        try:
    +            settings.USE_X_FORWARDED_HOST = True
    +
    +            # Check if X_FORWARDED_HOST is provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_X_FORWARDED_HOST': u'forward.com',
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            # X_FORWARDED_HOST is obeyed.
    +            self.assertEqual(request.get_host(), 'forward.com')
    +
    +            # Check if X_FORWARDED_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if HTTP_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com')
    +
    +            # Check if HTTP_HOST isn't provided, and we're on a nonstandard port
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 8042,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com:8042')
    +
    +        finally:
    +            settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
    
2f7fadc38efa

[1.3.X] Added protection against spoofing of X_FORWARDED_HOST headers. A security announcement will be made shortly.

https://github.com/django/djangoRussell Keith-MageeSep 10, 2011via ghsa
5 files changed · +112 5
  • django/conf/global_settings.py+2 0 modified
    @@ -399,6 +399,8 @@
     DEFAULT_TABLESPACE = ''
     DEFAULT_INDEX_TABLESPACE = ''
     
    +USE_X_FORWARDED_HOST = False
    +
     ##############
     # MIDDLEWARE #
     ##############
    
  • django/http/__init__.py+2 1 modified
    @@ -153,7 +153,8 @@ def __repr__(self):
         def get_host(self):
             """Returns the HTTP host using the environment or request headers."""
             # We try three options, in order of decreasing preference.
    -        if 'HTTP_X_FORWARDED_HOST' in self.META:
    +        if settings.USE_X_FORWARDED_HOST and (
    +            'HTTP_X_FORWARDED_HOST' in self.META):
                 host = self.META['HTTP_X_FORWARDED_HOST']
             elif 'HTTP_HOST' in self.META:
                 host = self.META['HTTP_HOST']
    
  • docs/ref/request-response.txt+5 4 modified
    @@ -191,10 +191,11 @@ Methods
     
     .. method:: HttpRequest.get_host()
     
    -    Returns the originating host of the request using information from the
    -    ``HTTP_X_FORWARDED_HOST`` and ``HTTP_HOST`` headers (in that order). If
    -    they don't provide a value, the method uses a combination of
    -    ``SERVER_NAME`` and ``SERVER_PORT`` as detailed in `PEP 333`_.
    +    Returns the originating host of the request using information from
    +    the ``HTTP_X_FORWARDED_HOST`` (if enabled in the settings) and ``HTTP_HOST``
    +    headers (in that order). If they don't provide a value, the method
    +    uses a combination of ``SERVER_NAME`` and ``SERVER_PORT`` as
    +    detailed in :pep:`3333`.
     
         .. _PEP 333: http://www.python.org/dev/peps/pep-0333/
     
    
  • docs/ref/settings.txt+13 0 modified
    @@ -1960,6 +1960,19 @@ in order to format numbers.
     
     See also :setting:`THOUSAND_SEPARATOR` and :setting:`NUMBER_GROUPING`.
     
    +.. setting:: USE_X_FORWARDED_HOST
    +
    +USE_X_FORWARDED_HOST
    +--------------------
    +
    +.. versionadded:: 1.3.1
    +
    +Default: ``False``
    +
    +A boolean that specifies whether to use the X-Forwarded-Host header in
    +preference to the Host header. This should only be enabled if a proxy
    +which sets this header is in use.
    +
     .. setting:: YEAR_MONTH_FORMAT
     
     YEAR_MONTH_FORMAT
    
  • tests/regressiontests/requests/tests.py+90 0 modified
    @@ -2,12 +2,14 @@
     from datetime import datetime, timedelta
     from StringIO import StringIO
     
    +from django.conf import settings
     from django.core.handlers.modpython import ModPythonRequest
     from django.core.handlers.wsgi import WSGIRequest, LimitedStream
     from django.http import HttpRequest, HttpResponse, parse_cookie
     from django.utils import unittest
     from django.utils.http import cookie_date
     
    +
     class RequestsTests(unittest.TestCase):
         def test_httprequest(self):
             request = HttpRequest()
    @@ -58,6 +60,94 @@ def test_httprequest_location(self):
             self.assertEqual(request.build_absolute_uri(location="/path/with:colons"),
                 'http://www.example.com/path/with:colons')
     
    +    def test_http_get_host(self):
    +        old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
    +        try:
    +            settings.USE_X_FORWARDED_HOST = False
    +
    +            # Check if X_FORWARDED_HOST is provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_X_FORWARDED_HOST': u'forward.com',
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            # X_FORWARDED_HOST is ignored.
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if X_FORWARDED_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if HTTP_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com')
    +
    +            # Check if HTTP_HOST isn't provided, and we're on a nonstandard port
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 8042,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com:8042')
    +
    +        finally:
    +            settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
    +
    +    def test_http_get_host_with_x_forwarded_host(self):
    +        old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
    +        try:
    +            settings.USE_X_FORWARDED_HOST = True
    +
    +            # Check if X_FORWARDED_HOST is provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_X_FORWARDED_HOST': u'forward.com',
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            # X_FORWARDED_HOST is obeyed.
    +            self.assertEqual(request.get_host(), 'forward.com')
    +
    +            # Check if X_FORWARDED_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'HTTP_HOST': u'example.com',
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'example.com')
    +
    +            # Check if HTTP_HOST isn't provided.
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 80,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com')
    +
    +            # Check if HTTP_HOST isn't provided, and we're on a nonstandard port
    +            request = HttpRequest()
    +            request.META = {
    +                u'SERVER_NAME': u'internal.com',
    +                u'SERVER_PORT': 8042,
    +            }
    +            self.assertEqual(request.get_host(), 'internal.com:8042')
    +
    +        finally:
    +            settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
    +
         def test_near_expiration(self):
             "Cookie will expire when an near expiration time is provided"
             response = HttpResponse()
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

15

News mentions

0

No linked articles in our index yet.