Files
vdm/daemon/docs
samiandClaude Sonnet 5 ab479e7885 daemon: fs/safepath — the saveDir/filename path-traversal boundary (security)
veloxd is the one process that turns an untrusted string into a
filesystem destination, and via capture.offer that string can come
from a web page. CLAUDE.md §4 and the M1 DoD both name this.

daemon/docs/safepath-adversarial.md is the spec, written before the
code the way EXT did for shouldCapture: 21 rows — .. traversal
(A1/A2), absolute-outside-roots (A3), prefix-match confusion (A4),
symlink-out (A7), TOCTOU on a created tail (A8), NUL/control bytes in
the leaf that CORE's fuzzer hit through Content-Disposition (A9/A10),
degenerate and overlong leaves (A11/A13), overlong dir component
(A14), symlinked root (A16), destination-is-a-file (A17), and the
legitimate cases that must still pass — non-ASCII (A18), redundant "."
(A19), trailing space/dot trimming (A20).

fs/safepath.cpp:
- sanitize_leaf: strip <0x20 and 0x7F, trim ws, strip trailing dots,
  reject ""/"."/".."/contains-'/', cap 255 UTF-8 bytes on a codepoint
  boundary. Mirrors core/src/net/content_disposition.cpp.
- canonicalize_root: expand ~ and realpath each allowedRoots entry
  once, so a symlinked root resolves to its target.
- resolve_target: reject relative saveDir and any ".." component
  lexically; if the dir exists, realpath + component-wise containment
  (a symlink that escapes is caught, one that stays inside passes); if
  a tail is missing, realpath+check the deepest existing ancestor then
  create the tail via an openat/mkdirat O_NOFOLLOW walk and re-derive
  the final path from the fd. Every failure is -32011 with data.path =
  the *original* saveDir (never the resolved path). Residual TOCTOU on
  a pre-existing intermediate dir is documented and closed by CORE's
  O_NOFOLLOW open of the file.

veloxd_fs static lib; veloxd_rpc links it for the download.add wiring
next. Test veloxd.safepath is the adversarial table, on a real temp
tree. ASan+UBSan and TSan clean; 33 daemon/cli tests green.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Upd9WhG9oppieig5nRDLig
2026-09-10 19:37:01 +04:00
..