wifi-densepose/v2/crates/wifi-densepose-sensing-server/src
rUv 72bbd256e7
fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616)
Reported by @bannned-bit. Five endpoints in
v2/crates/wifi-densepose-sensing-server embedded user-controlled
identifiers in format!() paths with no sanitization:

  recording.rs       POST   /api/v1/recording/start       (session_name)
  recording.rs       GET    /api/v1/recording/download/:id (id)
  recording.rs       DELETE /api/v1/recording/delete/:id   (id)
  model_manager.rs   POST   /api/v1/models/load           (model_id)
  training_api.rs    load_recording_frames                (dataset_ids[])

Each unauthenticated caller could:
- READ arbitrary files via ../../etc/passwd, ../../.env, etc.
- WRITE attacker-controlled JSONL via recording/start
- LOAD attacker-controlled .rvf model files
- DELETE arbitrary files the server process can touch

New `path_safety` module exports `safe_id(&str) -> Result<&str, PathSafetyError>`
that enforces the rejection envelope BEFORE any user input reaches a
format!() that builds a path:

  - Allowed character set: [A-Za-z0-9._-]
  - Reject leading '.' (rules out '.', '..', '.env', hidden files)
  - Reject empty strings
  - Reject anything > 64 bytes
  - Reject all whitespace, path separators, null bytes, non-ASCII

Applied at all 5 sites. Errors return 400 Bad Request (download) /
status:"error" JSON (others) — not panics.

9 unit tests in path_safety::tests cover:
  - accepts simple alphanumeric / hyphen / underscore / dot
  - rejects empty, leading dot, path separators ('/', '\'),
    null byte, whitespace, shell specials, non-ASCII (including
    fullwidth slash U+FF0F), too-long, boundary at MAX_ID_LEN

  test result: ok. 9 passed; 0 failed
  cargo build -p wifi-densepose-sensing-server --no-default-features: 33s

Fix-marker RuView#615 in scripts/fix-markers.json prevents removing the
guard at any of the 5 call sites. CHANGELOG entry under [Unreleased] /
Security documents the patched endpoints and the rejection envelope.

Severity: critical per reporter — five remotely-reachable paths to read,
write, or delete arbitrary files. Hot per-request paths, not edge cases.
2026-05-17 19:59:20 -04:00
..
adaptive_classifier.rs fix(sensing): adaptive_classifier sorts with unwrap_or(Equal) — NaN panic (closes #611) (#613) 2026-05-17 19:29:07 -04:00
bearer_auth.rs feat(docker+sensing-server): refresh Docker publish + opt-in bearer-token API auth 2026-05-13 08:52:25 -04:00
cli.rs v2: pin Rust 1.89 and fix sensing-server UI path when run from v2 (#523) 2026-05-17 18:00:36 -04:00
csi.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
dataset.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
embedding.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
field_bridge.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
graph_transformer.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
host_validation.rs fix(security): host-header allowlist on sensing-server HTTP + WS — DNS rebinding (#580) 2026-05-17 17:27:00 -04:00
introspection.rs feat(introspection): I6 — regime-changed signal + per-frame analyze + honest ADR-099 D8 amendment 2026-05-13 23:29:37 -04:00
lib.rs fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
main.rs v2: pin Rust 1.89 and fix sensing-server UI path when run from v2 (#523) 2026-05-17 18:00:36 -04:00
model_manager.rs fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
multistatic_bridge.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
path_safety.rs fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
pose.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
recording.rs fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
rvf_container.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
rvf_pipeline.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
sona.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
sparse_inference.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
tracker_bridge.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
trainer.rs chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00
training_api.rs fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
types.rs feat(ruvector,signal,sensing-server): ADR-084 Passes 1/1.5/2/3 — RaBitQ similarity sensor implementation (#435) 2026-04-26 02:21:35 -04:00
vital_signs.rs fix(vital_signs): use circular variance for wrapped phases (#595) 2026-05-17 17:02:53 -04:00