Files
ChatLab/packages/http-routes
ttsdj 89974f34e3 fix(cache): keep download writes inside the downloads directory
POST /_web/cache/save-to-downloads joined the caller-supplied `filename`
straight into the downloads directory:

    const filePath = path.join(downloadsDir, filename)

`path.join` collapses `..`, so `{"filename":"../escaped.txt"}` resolved
one level above the downloads directory and the route wrote
attacker-chosen bytes there, returning `{ success: true }`. Any client
that can reach the route could therefore write outside the downloads
directory as the app user.

The route is registered by the shared web routes on both CLI Web and the
Electron internal API, so the fix covers both. Its own siblings already
constrain this input — merge.ts and the CLI upload route both run the
name through `path.basename` — so the missing guard here was an
oversight rather than a documented allowance.

Reject anything that is not a plain file name, and join only the
validated basename. Names the app itself sends stay unchanged: every
caller (conversation export, SQL export, screen capture) already passes a
flat file name.
2026-09-10 16:17:10 +08:00
..