diff --git a/CHANGELOG.md b/CHANGELOG.md index c1cb61049dd82..7fdba3e3fb2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ No changes to highlight. ## Bug Fixes: -No changes to highlight. +- The `/file=` route no longer allows accessing dotfiles by [@akx](https://github.com/akx) in [PR 4302](https://github.com/gradio-app/gradio/pull/4302) ## Other Changes: diff --git a/gradio/routes.py b/gradio/routes.py index aad4270d16b8d..35feaf08f33d4 100644 --- a/gradio/routes.py +++ b/gradio/routes.py @@ -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 os.path.basename(abs_path).startswith("."): raise HTTPException(403, f"File not allowed: {path_or_url}.") in_app_dir = utils.abspath(app.cwd) in abs_path.parents diff --git a/test/test_routes.py b/test/test_routes.py index 918b459d7d97a..d53f7b23f5dd1 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -3,6 +3,7 @@ import os import sys import tempfile +from contextlib import closing from pathlib import Path from unittest.mock import patch @@ -645,3 +646,17 @@ 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") + 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(f"/file=.env").status_code == 403 + assert client.get(f"/file=subdir/.env").status_code == 403