You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While running an internal QE security audit (parallel qe-security-auditor + qe-pentest-validator pass triggered by the review of #442), we noticed that the wifi-densepose-sensing-server HTTP router is constructed without an auth layer on any of its mutating routes.
This is being filed as a design-intent question first, not a CVE — the sensing server is a LAN-only embedded service and an unauthenticated control plane may be entirely intentional for the deployment model. Flagging so we can either:
Confirm it's by design and document the threat model + recommended deployment posture, or
let http_app = Router::new().route("/api/v1/recording/start",post(start_recording)).route("/api/v1/recording/{id}",delete(delete_recording)).route("/api/v1/recording/{id}/download",get(download_recording)).route("/api/v1/models/load",post(load_model)).route("/api/v1/train/start",post(start_train)).route("/api/v1/calibration/start",post(start_calibration))// ... 40+ more routes.layer(SetResponseHeaderLayer::if_not_present(...))// ← only layer.with_state(state);
No tower_http::auth, no extractor checking a bearer header, no IP allow-list, no 127.0.0.1 bind. The default bind appears to be 0.0.0.0.
Routes affected (sample)
Mutating / state-changing routes with no auth:
POST /api/v1/recording/start, DELETE /api/v1/recording/{id}, GET /api/v1/recording/{id}/download
POST /api/v1/models/load
POST /api/v1/train/start
POST /api/v1/calibration/start
WS /ws/sensing (live CSI stream)
~40 more under /api/v1/*
Theoretical impact (LAN-adjacent attacker)
If the deployment is exposed to any untrusted device on the same network segment (e.g., guest WiFi, shared lab LAN), an unauthenticated client could:
Start, stop, download, or delete recordings.
Load arbitrary model paths (loader-permissiveness depends on internal validation).
Trigger training runs.
Stream live CSI from /ws/sensing (CSI can be reduced to coarse pose/presence — privacy-relevant).
If this is only ever deployed on a trusted LAN behind a hardware firewall (which is plausible for a research/sensing rig), the practical risk is much lower.
Is the sensing-server intended to be unauth on a trusted LAN only? If yes — should we (a) document this in the user guide / readme as a deployment requirement, and (b) bind to 127.0.0.1 by default with an explicit --bind 0.0.0.0 opt-in?
If auth is wanted, what's the preferred shape? Bearer token from a config file, mTLS, an IP allow-list, or join the existing JWT scheme used by v1/src/api?
Related: the ESP32 OTA path (firmware/esp32-csi-node/main/ota_update.c:44-49) has the same default-permissive shape — if (s_ota_psk[0] == '\0') return true;. Same design-intent question applies there: is the dev-default intentional?
Adjacent (already fixable, non-blocking on the auth question)
Independently of the auth model, three sites in the same crate have a path-traversal anti-pattern that should be fixed regardless because they trust user-supplied id in path joins:
Sibling delete_model at main.rs:2796-2804 already does the right thing (sanitises via Path::file_name()); these three callsites just weren't updated. Worth pulling into a small follow-up PR since the fix is mechanical and uncontroversial.
Context
While running an internal QE security audit (parallel
qe-security-auditor+qe-pentest-validatorpass triggered by the review of #442), we noticed that thewifi-densepose-sensing-serverHTTP router is constructed without an auth layer on any of its mutating routes.This is being filed as a design-intent question first, not a CVE — the sensing server is a LAN-only embedded service and an unauthenticated control plane may be entirely intentional for the deployment model. Flagging so we can either:
Evidence
rust-port/wifi-densepose-rs/crates/wifi-densepose-sensing-server/src/main.rs:4750-4810:No
tower_http::auth, no extractor checking a bearer header, no IP allow-list, no127.0.0.1bind. The default bind appears to be0.0.0.0.Routes affected (sample)
Mutating / state-changing routes with no auth:
POST /api/v1/recording/start,DELETE /api/v1/recording/{id},GET /api/v1/recording/{id}/downloadPOST /api/v1/models/loadPOST /api/v1/train/startPOST /api/v1/calibration/startWS /ws/sensing(live CSI stream)/api/v1/*Theoretical impact (LAN-adjacent attacker)
If the deployment is exposed to any untrusted device on the same network segment (e.g., guest WiFi, shared lab LAN), an unauthenticated client could:
/ws/sensing(CSI can be reduced to coarse pose/presence — privacy-relevant).If this is only ever deployed on a trusted LAN behind a hardware firewall (which is plausible for a research/sensing rig), the practical risk is much lower.
Questions for @ruvnet
127.0.0.1by default with an explicit--bind 0.0.0.0opt-in?v1/src/api?firmware/esp32-csi-node/main/ota_update.c:44-49) has the same default-permissive shape —if (s_ota_psk[0] == '\0') return true;. Same design-intent question applies there: is the dev-default intentional?Adjacent (already fixable, non-blocking on the auth question)
Independently of the auth model, three sites in the same crate have a path-traversal anti-pattern that should be fixed regardless because they trust user-supplied
idin path joins:crates/wifi-densepose-sensing-server/src/main.rs:2926-2945(start_recording)crates/wifi-densepose-sensing-server/src/recording.rs:345-387(download_recording)crates/wifi-densepose-sensing-server/src/recording.rs:389-425(delete_recording)Sibling
delete_modelatmain.rs:2796-2804already does the right thing (sanitises viaPath::file_name()); these three callsites just weren't updated. Worth pulling into a small follow-up PR since the fix is mechanical and uncontroversial.References
docs/security/audit-application.md(§Z-1, §P-1),docs/security/audit-exploitability.md(§NEW-1, §NEW-2),docs/security/audit-deep.md(§2, §3)Suggested labels
security,discussion,needs-design-decision