Skip to content

Commit

Permalink
Don't allow dotfiles for /file= route (#4303)
Browse files Browse the repository at this point in the history
* Don't allow dotfiles or files in "dot directories" for /file=

* update guide

---------

Co-authored-by: Abubakar Abid <[email protected]>
  • Loading branch information
akx and abidlabs authored May 30, 2023
1 parent fc3bbca commit 7781665
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
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

0 comments on commit 7781665

Please sign in to comment.