Skip to content
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

Allow staticfiles to follow symlinks outside directory #1377

Merged
merged 17 commits into from May 28, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions starlette/staticfiles.py
Expand Up @@ -157,11 +157,13 @@ def lookup_path(
self, path: str
) -> typing.Tuple[str, typing.Optional[os.stat_result]]:
for directory in self.all_directories:
full_path = os.path.realpath(os.path.join(directory, path))
original_path = os.path.join(directory, path)
aminalaee marked this conversation as resolved.
Show resolved Hide resolved
full_path = os.path.realpath(original_path)
directory = os.path.realpath(directory)
if os.path.commonprefix([full_path, directory]) != directory:
is_external = os.path.commonprefix([full_path, directory]) != directory
if is_external and not os.path.islink(original_path):
# Don't allow misbehaving clients to break out of the static files
# directory.
# directory if not following symlinks.
continue
try:
return full_path, os.stat(full_path)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_staticfiles.py
Expand Up @@ -441,3 +441,26 @@ def mock_timeout(*args, **kwargs):
response = client.get("/example.txt")
assert response.status_code == 500
assert response.text == "Internal Server Error"


def test_staticfiles_follows_symlinks_to_break_out_of_dir(tmpdir, test_client_factory):
aminalaee marked this conversation as resolved.
Show resolved Hide resolved
statics_path = os.path.join(tmpdir, "statics")
os.mkdir(statics_path)

symlink_path = os.path.join(tmpdir, "symlink")
os.mkdir(symlink_path)

symlink_file_path = os.path.join(symlink_path, "index.html")
with open(symlink_file_path, "w") as file:
file.write("<h1>Hello</h1>")

statics_file_path = os.path.join(statics_path, "index.html")
os.symlink(symlink_file_path, statics_file_path)

app = StaticFiles(directory=statics_path)
client = test_client_factory(app)

response = client.get("/index.html")
assert response.url == "http://testserver/index.html"
assert response.status_code == 200
assert response.text == "<h1>Hello</h1>"