Repository navigation
fix: reject path separators in get_static_doc names #2834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -34,6 +34,7 @@ | |||||
| import pickle | ||||||
| import re | ||||||
| import sys | ||||||
| import tempfile | ||||||
| import unittest | ||||||
| from unittest import mock | ||||||
| import urllib | ||||||
|
|
@@ -83,7 +84,7 @@ | |||||
| build_from_document, | ||||||
| key2param, | ||||||
| ) | ||||||
| from googleapiclient.discovery_cache import DISCOVERY_DOC_MAX_AGE | ||||||
| from googleapiclient.discovery_cache import DISCOVERY_DOC_DIR, DISCOVERY_DOC_MAX_AGE | ||||||
| from googleapiclient.discovery_cache.base import Cache | ||||||
| from googleapiclient.errors import ( | ||||||
| HttpError, | ||||||
|
|
@@ -1499,6 +1500,23 @@ def test_unknown_api_when_static_discovery_true(self): | |||||
| with self.assertRaises(UnknownApiNameOrVersion): | ||||||
| build("doesnotexist", "v3", cache_discovery=False, static_discovery=True) | ||||||
|
|
||||||
| def test_static_discovery_does_not_read_outside_of_documents_dir(self): | ||||||
| http = HttpMockSequence([({"status": "400"}, "")]) | ||||||
| with tempfile.TemporaryDirectory() as tmpdir: | ||||||
| with open(os.path.join(tmpdir, "zoo.v1.json"), "w") as f: | ||||||
| f.write(read_datafile("zoo.json")) | ||||||
| outside = os.path.join(tmpdir, "zoo") | ||||||
| # Both an absolute path and one relative to the bundled documents. | ||||||
| for name in (outside, os.path.relpath(outside, DISCOVERY_DOC_DIR)): | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To ensure that the platform-independent path traversal protection works correctly across all environments, we should explicitly test a path containing backslashes (
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On Linux/macOS that case would pass trivially, since |
||||||
| with self.assertRaises(UnknownApiNameOrVersion): | ||||||
| build( | ||||||
| name, | ||||||
| "v1", | ||||||
| http=http, | ||||||
| cache_discovery=False, | ||||||
| static_discovery=True, | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| class DictCache(Cache): | ||||||
| def __init__(self): | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
os.path.basenameto detect path separators is platform-dependent. On Unix-like systems,os.path.basenamedoes not recognize backslashes (\) as directory separators, whereas on Windows it does. To ensure robust, platform-independent protection against directory traversal attacks, we should explicitly reject both forward slashes (/) and backslashes (\) in the document name, regardless of the operating system the code is running on.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The platform dependence is intentional here.
os.pathisntpathon Windows, wherebasenamealready treats\,/, drive prefixes (C:zoo) and UNC roots as separators, so..\..\zoo.v1.jsongets rejected. On POSIX a backslash is just a filename character, soopen()would look for a file literally named..\..\zoo.v1.jsoninsideDISCOVERY_DOC_DIRand can't leave the directory. Rejecting\explicitly wouldn't close any extra path, so I've kept the check as is.