Pyramid static view path traversal up one directory
Description
Pyramid 2.0.0/2.0.1 path traversal via null-byte truncation in Python 3.11's os.path.normpath allows disclosure of index.html one directory above static view path.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Pyramid 2.0.0/2.0.1 path traversal via null-byte truncation in Python 3.11's os.path.normpath allows disclosure of index.html one directory above static view path.
Vulnerability
Overview
CVE-2023-40587 is a path traversal vulnerability in the Pyramid web framework (versions 2.0.0 and 2.0.1) that specifically affects users running Python 3.11. The root cause lies in a behavioral change in Python 3.11's os.path.normpath function, which truncates paths at the first null byte (\x00). When Pyramid's static view processes a crafted path containing a null byte, the truncated path can traverse one directory upward, potentially exposing an index.html file located exactly one level above the static view's configured filesystem path [1][2].
Exploitation
Conditions
To exploit this vulnerability, an attacker must have access to a Pyramid static view configured with a full filesystem path (e.g., config.add_static_view(name='static', path='/usr/src/app/static')). The attacker sends a request with a path containing a null byte, such as ..\x00/, which after truncation resolves to the parent directory. The attack only works if an index.html file exists in that parent directory; no other files can be accessed [2]. No authentication is required if the static view is publicly accessible.
Impact
The impact is limited to the disclosure of a single index.html file located one directory above the static view's root. While this may seem minor, it could leak sensitive information if the file contains configuration details, API keys, or other secrets. The vulnerability does not allow arbitrary file traversal or remote code execution [1][2].
Mitigation and
Patches
Pyramid version 2.0.2 rejects any path containing a null byte as a precaution [4]. The underlying Python issue (CPython #106242) has been fixed in Python 3.11.5 and 3.12.0rc2, restoring the pre-3.11 behavior where null bytes are not truncated [3]. Users unable to upgrade immediately can downgrade to Python 3.10 or wait for the patched Python versions [2].
AI Insight generated on May 20, 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.
| Package | Affected versions | Patched versions |
|---|---|---|
pyramidPyPI | >= 2.0.0, < 2.0.2 | 2.0.2 |
Affected products
2Patches
1347d7750da6ffix: reject NUL character as path element
3 files changed · +19 −5
src/pyramid/static.py+5 −5 modified@@ -260,12 +260,12 @@ def _add_vary(response, option): response.vary = vary -_seps = {'/', os.sep} +_invalid_element_chars = {'/', os.sep, '\x00'} -def _contains_slash(item): - for sep in _seps: - if sep in item: +def _contains_invalid_element_char(item): + for invalid_element_char in _invalid_element_chars: + if invalid_element_char in item: return True @@ -279,7 +279,7 @@ def _secure_path(path_tuple): # unless someone screws up the traversal_path code # (request.subpath is computed via traversal_path too) return None - if any([_contains_slash(item) for item in path_tuple]): + if any([_contains_invalid_element_char(item) for item in path_tuple]): return None encoded = '/'.join(path_tuple) # will be unicode return encoded
tests/fixtures/index.html+1 −0 added@@ -0,0 +1 @@ +<h1>DON'T GO HERE</h1>
tests/test_static.py+13 −0 modified@@ -104,6 +104,19 @@ def test_oob_os_sep(self): self.assertRaises(HTTPNotFound, inst, context, request) + def test_oob_nul_char(self): + import os + + inst = self._makeOne(f'{os.getcwd()}/tests/fixtures/static') + dds = '..\x00/' + request = self._makeRequest( + {'PATH_INFO': f'/{dds}'} + ) + context = DummyContext() + from pyramid.httpexceptions import HTTPNotFound + + self.assertRaises(HTTPNotFound, inst, context, request) + def test_resource_doesnt_exist(self): inst = self._makeOne('tests:fixtures/static') request = self._makeRequest({'PATH_INFO': '/notthere'})
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-j8g2-6fc7-q8f8ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-40587ghsaADVISORY
- github.com/Pylons/pyramid/commit/347d7750da6f45c7436dd0c31468885cc9343c85ghsax_refsource_MISCWEB
- github.com/Pylons/pyramid/security/advisories/GHSA-j8g2-6fc7-q8f8ghsax_refsource_CONFIRMWEB
- github.com/python/cpython/issues/106242ghsax_refsource_MISCWEB
- github.com/python/cpython/pull/106816ghsax_refsource_MISCWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/LYSDTQ7NP5GHPQ7HBE47MBJQK7YEIYMFghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/OQIPHQTM3XE5NIEXCTQFV2J2RK2YUSMTghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/LYSDTQ7NP5GHPQ7HBE47MBJQK7YEIYMF/mitre
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/OQIPHQTM3XE5NIEXCTQFV2J2RK2YUSMT/mitre
News mentions
0No linked articles in our index yet.