Skip to content

Sensing-server REST API: confirm intended auth model for /api/v1/* routes #443

@proffesor-for-testing

Description

@proffesor-for-testing

Context

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
  • Add an auth layer if it isn't.

Evidence

rust-port/wifi-densepose-rs/crates/wifi-densepose-sensing-server/src/main.rs:4750-4810:

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.

Questions for @ruvnet

  1. 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?
  2. 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?
  3. 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:

  • 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_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.

References

  • Internal audit reports: 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)
  • Triggered by: Potential security exposure in RuView #442

Suggested labels

security, discussion, needs-design-decision

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions