Skip to content

Commit 2ee51ec

Browse files
Yann-PCarreau
authored andcommitted
fix(CVE-2026-35397): path traversal when target dir starts with root dir
1 parent 057869a commit 2ee51ec

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

jupyter_server/services/contents/fileio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def _get_os_path(self, path):
322322
except ValueError:
323323
raise HTTPError(404, f"{path} is not a valid path") from None
324324

325-
if not (os.path.abspath(os_path) + os.path.sep).startswith(root):
325+
if not (os.path.abspath(os_path) + os.path.sep).startswith(root + os.path.sep):
326326
raise HTTPError(404, "%s is outside root contents directory" % path)
327327
return os_path
328328

tests/services/contents/test_fileio.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,23 @@ async def test_AsyncFileManagerMixin_read_file_no_raw(tmpdir):
279279
answer = await mixin._read_file(file_path, "text")
280280

281281
assert len(answer) == 2
282+
283+
284+
# CVE-2026-35397 : Path traversal via incorrect startswith() root directory check
285+
# allows access to sibling directories
286+
def test_path_traversal_when_sibling_dir_starts_with_root_dir(tmpdir):
287+
class FileManagerMixinTest(FileManagerMixin):
288+
root_dir = tmpdir / "test"
289+
290+
# testtest starts with test, which was what allowed access to the sibling directory
291+
victim_file_path = tmpdir / "testtest/secret.txt"
292+
victim_file_path.write_text("secret_file_content", "utf8", ensure=True)
293+
294+
mixin = FileManagerMixinTest()
295+
mixin.log = logging.getLogger()
296+
297+
with pytest.raises(HTTPError) as err:
298+
mixin._get_os_path("../testtest/secret.txt")
299+
300+
assert err.value.status_code == 404
301+
assert "outside root contents directory" in str(err.value)

0 commit comments

Comments
 (0)