VYPR
Moderate severityNVD Advisory· Published Jun 8, 2021· Updated Aug 3, 2024

CVE-2021-33203

CVE-2021-33203

Description

Django before 2.2.24, 3.x before 3.1.12, and 3.2.x before 3.2.4 has a potential directory traversal via django.contrib.admindocs. Staff members could use the TemplateDetailView view to check the existence of arbitrary files. Additionally, if (and only if) the default admindocs templates have been customized by application developers to also show file contents, then not only the existence but also the file contents would have been exposed. In other words, there is directory traversal outside of the template root directories.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Django admindocs TemplateDetailView allows staff to check existence of arbitrary files, and potentially read them if templates are customized.

Vulnerability

CVE-2021-33203 is a directory traversal vulnerability in Django's django.contrib.admindocs module, specifically in the TemplateDetailView view [1][2]. The view constructs a file path by concatenating a template directory with a user-supplied template name using Path(directory) / template without sanitization, allowing path traversal sequences like ../ to escape the intended template root directories [3][4]. Affected versions are Django before 2.2.24, 3.x before 3.1.12, and 3.2.x before 3.2.4 [1][2].

Exploitation

An attacker must be a staff member (authenticated with staff status) to access the admindocs views [1][2]. By crafting a template parameter with directory traversal sequences (e.g., ../../etc/passwd), the attacker can check the existence of arbitrary files on the server. If the application developers have customized the default admindocs templates to also display file contents (not the default behavior), then the attacker could also read the contents of those files [1][2].

Impact

Successful exploitation results in information disclosure: the attacker can determine whether arbitrary files exist on the server. In the customized-template scenario, the attacker can read the contents of those files, potentially exposing sensitive data such as configuration files, source code, or credentials [1][2]. No code execution or privilege escalation is reported.

Mitigation

The vulnerability is fixed in Django 2.2.24, 3.1.12, and 3.2.4 [1][2]. The fix introduces safe_join from django.utils._os to sanitize the path and ensure only files within the template root directories can be accessed [3][4]. Users should upgrade to the patched versions. No workaround is available for unpatched versions; restricting staff access to admindocs may reduce risk but does not eliminate the vulnerability.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
DjangoPyPI
< 2.2.242.2.24
DjangoPyPI
>= 3.0, < 3.1.123.1.12
DjangoPyPI
>= 3.2, < 3.2.43.2.4

Affected products

166

Patches

3
053cc9534d17

[2.2.x] Fixed CVE-2021-33203 -- Fixed potential path-traversal via admindocs' TemplateDetailView.

https://github.com/django/djangoFlorian ApollonerMay 25, 2021via ghsa
3 files changed · +29 2
  • django/contrib/admindocs/views.py+2 1 modified
    @@ -15,6 +15,7 @@
     from django.http import Http404
     from django.template.engine import Engine
     from django.urls import get_mod_func, get_resolver, get_urlconf
    +from django.utils._os import safe_join
     from django.utils.decorators import method_decorator
     from django.utils.inspect import (
         func_accepts_kwargs, func_accepts_var_args, get_func_full_args,
    @@ -328,7 +329,7 @@ def get_context_data(self, **kwargs):
             else:
                 # This doesn't account for template loaders (#24128).
                 for index, directory in enumerate(default_engine.dirs):
    -                template_file = Path(directory) / template
    +                template_file = Path(safe_join(directory, template))
                     if template_file.exists():
                         with template_file.open() as f:
                             template_contents = f.read()
    
  • docs/releases/2.2.24.txt+11 1 modified
    @@ -6,4 +6,14 @@ Django 2.2.24 release notes
     
     Django 2.2.24 fixes two security issues in 2.2.23.
     
    -...
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    
  • tests/admin_docs/test_views.py+16 0 modified
    @@ -134,6 +134,22 @@ def test_no_sites_framework(self):
             self.assertContains(response, 'View documentation')
     
     
    +@unittest.skipUnless(utils.docutils_is_available, 'no docutils installed.')
    +class AdminDocViewDefaultEngineOnly(TestDataMixin, AdminDocsTestCase):
    +
    +    def setUp(self):
    +        self.client.force_login(self.superuser)
    +
    +    def test_template_detail_path_traversal(self):
    +        cases = ['/etc/passwd', '../passwd']
    +        for fpath in cases:
    +            with self.subTest(path=fpath):
    +                response = self.client.get(
    +                    reverse('django-admindocs-templates', args=[fpath]),
    +                )
    +                self.assertEqual(response.status_code, 400)
    +
    +
     @override_settings(TEMPLATES=[{
         'NAME': 'ONE',
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
    
20c67a0693c4

[3.1.x] Fixed CVE-2021-33203 -- Fixed potential path-traversal via admindocs' TemplateDetailView.

https://github.com/django/djangoFlorian ApollonerMay 17, 2021via ghsa
4 files changed · +40 3
  • django/contrib/admindocs/views.py+2 1 modified
    @@ -16,6 +16,7 @@
     from django.http import Http404
     from django.template.engine import Engine
     from django.urls import get_mod_func, get_resolver, get_urlconf
    +from django.utils._os import safe_join
     from django.utils.decorators import method_decorator
     from django.utils.inspect import (
         func_accepts_kwargs, func_accepts_var_args, get_func_full_args,
    @@ -329,7 +330,7 @@ def get_context_data(self, **kwargs):
             else:
                 # This doesn't account for template loaders (#24128).
                 for index, directory in enumerate(default_engine.dirs):
    -                template_file = Path(directory) / template
    +                template_file = Path(safe_join(directory, template))
                     if template_file.exists():
                         template_contents = template_file.read_text()
                     else:
    
  • docs/releases/2.2.24.txt+11 1 modified
    @@ -6,4 +6,14 @@ Django 2.2.24 release notes
     
     Django 2.2.24 fixes two security issues in 2.2.23.
     
    -...
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    
  • docs/releases/3.1.12.txt+11 1 modified
    @@ -6,4 +6,14 @@ Django 3.1.12 release notes
     
     Django 3.1.12 fixes two security issues in 3.1.11.
     
    -...
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    
  • tests/admin_docs/test_views.py+16 0 modified
    @@ -137,6 +137,22 @@ def test_no_sites_framework(self):
             self.assertContains(response, 'View documentation')
     
     
    +@unittest.skipUnless(utils.docutils_is_available, 'no docutils installed.')
    +class AdminDocViewDefaultEngineOnly(TestDataMixin, AdminDocsTestCase):
    +
    +    def setUp(self):
    +        self.client.force_login(self.superuser)
    +
    +    def test_template_detail_path_traversal(self):
    +        cases = ['/etc/passwd', '../passwd']
    +        for fpath in cases:
    +            with self.subTest(path=fpath):
    +                response = self.client.get(
    +                    reverse('django-admindocs-templates', args=[fpath]),
    +                )
    +                self.assertEqual(response.status_code, 400)
    +
    +
     @override_settings(TEMPLATES=[{
         'NAME': 'ONE',
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
    
dfaba12cda06

[3.2.x] Fixed CVE-2021-33203 -- Fixed potential path-traversal via admindocs' TemplateDetailView.

https://github.com/django/djangoFlorian ApollonerMay 17, 2021via ghsa
5 files changed · +52 3
  • django/contrib/admindocs/views.py+2 1 modified
    @@ -16,6 +16,7 @@
     from django.http import Http404
     from django.template.engine import Engine
     from django.urls import get_mod_func, get_resolver, get_urlconf
    +from django.utils._os import safe_join
     from django.utils.decorators import method_decorator
     from django.utils.inspect import (
         func_accepts_kwargs, func_accepts_var_args, get_func_full_args,
    @@ -329,7 +330,7 @@ def get_context_data(self, **kwargs):
             else:
                 # This doesn't account for template loaders (#24128).
                 for index, directory in enumerate(default_engine.dirs):
    -                template_file = Path(directory) / template
    +                template_file = Path(safe_join(directory, template))
                     if template_file.exists():
                         template_contents = template_file.read_text()
                     else:
    
  • docs/releases/2.2.24.txt+11 1 modified
    @@ -6,4 +6,14 @@ Django 2.2.24 release notes
     
     Django 2.2.24 fixes two security issues in 2.2.23.
     
    -...
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    
  • docs/releases/3.1.12.txt+11 1 modified
    @@ -6,4 +6,14 @@ Django 3.1.12 release notes
     
     Django 3.1.12 fixes two security issues in 3.1.11.
     
    -...
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    
  • docs/releases/3.2.4.txt+12 0 modified
    @@ -6,6 +6,18 @@ Django 3.2.4 release notes
     
     Django 3.2.4 fixes two security issues and several bugs in 3.2.3.
     
    +CVE-2021-33203: Potential directory traversal via ``admindocs``
    +===============================================================
    +
    +Staff members could use the :mod:`~django.contrib.admindocs`
    +``TemplateDetailView`` view to check the existence of arbitrary files.
    +Additionally, if (and only if) the default admindocs templates have been
    +customized by the developers to also expose the file contents, then not only
    +the existence but also the file contents would have been exposed.
    +
    +As a mitigation, path sanitation is now applied and only files within the
    +template root directories can be loaded.
    +
     Bugfixes
     ========
     
    
  • tests/admin_docs/test_views.py+16 0 modified
    @@ -137,6 +137,22 @@ def test_no_sites_framework(self):
             self.assertContains(response, 'View documentation')
     
     
    +@unittest.skipUnless(utils.docutils_is_available, 'no docutils installed.')
    +class AdminDocViewDefaultEngineOnly(TestDataMixin, AdminDocsTestCase):
    +
    +    def setUp(self):
    +        self.client.force_login(self.superuser)
    +
    +    def test_template_detail_path_traversal(self):
    +        cases = ['/etc/passwd', '../passwd']
    +        for fpath in cases:
    +            with self.subTest(path=fpath):
    +                response = self.client.get(
    +                    reverse('django-admindocs-templates', args=[fpath]),
    +                )
    +                self.assertEqual(response.status_code, 400)
    +
    +
     @override_settings(TEMPLATES=[{
         'NAME': 'ONE',
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
    

Vulnerability mechanics

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

References

16

News mentions

0

No linked articles in our index yet.