Skip to content

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

Description

@Mefisto04

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:

# 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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions