AnswerDotAI / AnswerDotAI/fasthtml

[BUG] static_route_exts / static_route allow directory traversal via fname path segments

Open Beginner friendly
#912 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Jupyter Notebook
Stars
7k
Forks
319
Avg merge
28m
Merged PRs (30d)
3

Description

**Describe the bug**

`static_route_exts()` and `static_route()` build file paths by string concatenation without normalizing or constraining `fname` to stay under `static_path`:

```python
# fasthtml/core.py
FileResponse(f'{static_path}/{fname}.{ext}') # static_route_exts
FileResponse(f'{static_path}/{fname}{ext}') # static_route
```

Because `{fname:path}` can contain `..` segments, a request may escape the intended static directory if the target file exists on disk.

**Minimal Reproducible Example**

```python
import os, tempfile
from starlette.testclient import TestClient
from fasthtml.common import fast_app

tmpdir = tempfile.mkdtemp()
parent = os.path.dirname(tmpdir)
open(os.path.join(parent, "secret.txt"), "w").write("LEAKED")

app, rt = fast_app(static_path=tmpdir)
client = TestClient(app)
resp = client.get("/../secret.txt")
print(resp.status_code, resp.text)
```

**Expected behavior**

Static handlers should only serve files whose resolved path is inside `static_path`. Paths with `..` should return 404.

**Actual behavior**

`FileResponse` is built with a path outside `static_path`. `_resp()` only checks `os.path.exists(resp.path)` without verifying the path stays within the static root.

**Suggested fix**

Resolve with `Path(static_path, fname).resolve()` and verify `resolved.is_relative_to(Path(static_path).resolve())`.

**Environment Information**

- fasthtml version: 0.14.x (main)
- Python: 3.11+

**Confirmation**

- [x] I have read the FAQ (https://docs.fastht.ml/explains/faq.html)
- [x] I have provided a minimal reproducible example
- [x] I understand that this is a volunteer open source project with no commercial support.

Contributor guide

Open the contributing guide

Research direction

Start in fasthtml/core.py with static_route_exts(), static_route(), and _resp(), then run the minimal Starlette TestClient reproduction from the issue. Confirm that paths containing .. return 404 while files within static_path remain available; the resolved path must stay under the static root.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.