AnswerDotAI / AnswerDotAI/fasthtml
[BUG] static_route_exts / static_route allow directory traversal via fname path segments
- 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
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