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

Don't allow dotfiles for /file= route #4303

Merged
merged 2 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

## Breaking Changes:

No changes to highlight.
- The `/file=` route no longer allows accessing dotfiles or files in "dot directories" by [@akx](https://github.com/akx) in [PR 4303](https://github.com/gradio-app/gradio/pull/4303)

# 3.32.0

Expand Down
2 changes: 1 addition & 1 deletion gradio/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ async def file(path_or_url: str, request: fastapi.Request):
utils.is_in_or_equal(abs_path, blocked_path)
for blocked_path in blocks.blocked_paths
)
if in_blocklist:
if in_blocklist or any(part.startswith(".") for part in abs_path.parts):
raise HTTPException(403, f"File not allowed: {path_or_url}.")

in_app_dir = utils.abspath(app.cwd) in abs_path.parents
Expand Down
20 changes: 14 additions & 6 deletions guides/01_getting-started/03_sharing-your-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,22 @@ Note that this approach also allows you run your Gradio apps on custom paths (`h

## Security and File Access

Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) **exposes** certain files on the host machine to users of your Gradio app. This is done so that Gradio apps are able to display output files created by Gradio or created by your prediction function.
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) **exposes** certain files on the host machine to users of your Gradio app.

In particular, Gradio apps grant users access to three kinds of files:
In particular, Gradio apps ALLOW users to access to three kinds of files:

* Files in the same folder (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is `/home/usr/scripts/project/app.py` and you launch it from `/home/usr/scripts/project/`, then users of your shared Gradio app will be able to access any files inside `/home/usr/scripts/project/`. This is needed so that you can easily reference these files in your Gradio app.
* **Files in the same directory (or a subdirectory) of where the Gradio script is launched from.** For example, if the path to your gradio scripts is `/home/usr/scripts/project/app.py` and you launch it from `/home/usr/scripts/project/`, then users of your shared Gradio app will be able to access any files inside `/home/usr/scripts/project/`. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's `examples`).

* Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR to an absolute path, such as `/home/usr/scripts/project/temp/`.
* **Temporary files created by Gradio.** These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable `GRADIO_TEMP_DIR` to an absolute path, such as `/home/usr/scripts/project/temp/`.

* Files that you explicitly allow via the `allowed_paths` parameter in `launch()`. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
* **Files that you explicitly allow via the `allowed_paths` parameter in `launch()`**. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).

Users should NOT be able to access other arbitrary paths on the host. Furthermore, as a security measure, you can also **block** specific files or directories from being able to be accessed by users. To do this, pass in a list of additional directories or exact filepaths to the `blocked_paths` parameter in `launch()`. This parameter takes precedence over the files that Gradio exposes by default or by the `allowed_paths`.
Gradio DOES NOT ALLOW access to:

* **Dotfiles** (any files whose name begins with `'.'`) or any files that are contained in any directory whose name begins with `'.'`

* **Files that you explicitly allow via the `blocked_paths` parameter in `launch()`**. You can pass in a list of additional directories or exact filepaths to the `blocked_paths` parameter in `launch()`. This parameter takes precedence over the files that Gradio exposes by default or by the `allowed_paths`.

* **Any other paths on the host machine**. Users should NOT be able to access other arbitrary paths on the host.

Please make sure you are running the latest version of `gradio` for these security settings to apply.
20 changes: 20 additions & 0 deletions test/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import sys
import tempfile
from contextlib import closing
from pathlib import Path
from unittest.mock import patch

Expand Down Expand Up @@ -645,3 +646,22 @@ def test_orjson_serialization():
response = test_client.get("/")
assert response.status_code == 200
demo.close()


def test_file_route_does_not_allow_dot_paths(tmp_path):
dot_file = tmp_path / ".env"
dot_file.write_text("secret=1234")
subdir = tmp_path / "subdir"
subdir.mkdir()
sub_dot_file = subdir / ".env"
sub_dot_file.write_text("secret=1234")
secret_sub_dir = tmp_path / ".versioncontrol"
secret_sub_dir.mkdir()
secret_sub_dir_regular_file = secret_sub_dir / "settings"
secret_sub_dir_regular_file.write_text("token = 8")
with closing(gr.Interface(lambda s: s.name, gr.File(), gr.File())) as io:
app, _, _ = io.launch(prevent_thread_lock=True)
client = TestClient(app)
assert client.get("/file=.env").status_code == 403
assert client.get("/file=subdir/.env").status_code == 403
assert client.get("/file=.versioncontrol/settings").status_code == 403