wifi-densepose/v2/crates/wifi-densepose-sensing-server
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
..
src fix(security): path-traversal guard on 5 sensing-server endpoints (closes #615) (#616) 2026-05-17 19:59:20 -04:00
tests feat(introspection): I6 — regime-changed signal + per-frame analyze + honest ADR-099 D8 amendment 2026-05-13 23:29:37 -04:00
Cargo.toml chore(deps): bump tower-http from 0.5.2 to 0.6.8 in /v2 (#483) 2026-05-17 18:08:04 -04:00
README.md chore(repo): rename rust-port/wifi-densepose-rs → v2/ (flatten to one level) (#427) 2026-04-25 21:28:13 -04:00

README.md

wifi-densepose-sensing-server

Crates.io Documentation License

Lightweight Axum server for real-time WiFi sensing with RuVector signal processing.

Overview

wifi-densepose-sensing-server is the operational backend for WiFi-DensePose. It receives raw CSI frames from ESP32 hardware over UDP, runs them through the RuVector-powered signal processing pipeline, and broadcasts processed sensing updates to browser clients via WebSocket. A built-in static file server hosts the sensing UI on the same port.

The crate ships both a library (wifi_densepose_sensing_server) exposing the training and inference modules, and a binary (sensing-server) that starts the full server stack.

Integrates wifi-densepose-wifiscan for multi-BSSID WiFi scanning per ADR-022 Phase 3.

Features

  • UDP CSI ingestion -- Receives ESP32 CSI frames on port 5005 and parses them into the internal CsiFrame representation.
  • Vital sign detection -- Pure-Rust FFT-based breathing rate (0.1--0.5 Hz) and heart rate (0.67--2.0 Hz) estimation from CSI amplitude time series (ADR-021).
  • RVF container -- Standalone binary container format for packaging model weights, metadata, and configuration into a single .rvf file with 64-byte aligned segments.
  • RVF pipeline -- Progressive model loading with streaming segment decoding.
  • Graph Transformer -- Cross-attention bottleneck between antenna-space CSI features and the COCO 17-keypoint body graph, followed by GCN message passing (ADR-023 Phase 2). Pure std, no ML dependencies.
  • SONA adaptation -- LoRA + EWC++ online adaptation for environment drift without catastrophic forgetting (ADR-023 Phase 5).
  • Contrastive CSI embeddings -- Self-supervised SimCLR-style pretraining with InfoNCE loss, projection head, fingerprint indexing, and cross-modal pose alignment (ADR-024).
  • Sparse inference -- Activation profiling, sparse matrix-vector multiply, INT8/FP16 quantization, and a full sparse inference engine for edge deployment (ADR-023 Phase 6).
  • Dataset pipeline -- Training dataset loading and batching.
  • Multi-BSSID scanning -- Windows netsh integration for BSSID discovery via wifi-densepose-wifiscan (ADR-022).
  • WebSocket broadcast -- Real-time sensing updates pushed to all connected clients at ws://localhost:8765/ws/sensing.
  • Static file serving -- Hosts the sensing UI on port 8080 with CORS headers.

Modules

Module Description
vital_signs Breathing and heart rate extraction via FFT spectral analysis
rvf_container RVF binary format builder and reader
rvf_pipeline Progressive model loading from RVF containers
graph_transformer Graph Transformer + GCN for CSI-to-pose estimation
trainer Training loop orchestration
dataset Training data loading and batching
sona LoRA adapters and EWC++ continual learning
sparse_inference Neuron profiling, sparse matmul, INT8/FP16 quantization
embedding Contrastive CSI embedding model and fingerprint index

Quick Start

# Build the server
cargo build -p wifi-densepose-sensing-server

# Run with default settings (HTTP :8080, UDP :5005, WS :8765)
cargo run -p wifi-densepose-sensing-server

# Run with custom ports
cargo run -p wifi-densepose-sensing-server -- \
    --http-port 9000 \
    --udp-port 5005 \
    --static-dir ./ui

Using as a library

use wifi_densepose_sensing_server::vital_signs::VitalSignDetector;

// Create a detector with 20 Hz sample rate
let mut detector = VitalSignDetector::new(20.0);

// Feed CSI amplitude samples
for amplitude in csi_amplitudes.iter() {
    detector.push_sample(*amplitude);
}

// Extract vital signs
if let Some(vitals) = detector.detect() {
    println!("Breathing: {:.1} BPM", vitals.breathing_rate_bpm);
    println!("Heart rate: {:.0} BPM", vitals.heart_rate_bpm);
}

Architecture

ESP32 ──UDP:5005──> [ CSI Receiver ]
                          |
                    [ Signal Pipeline ]
                    (vital_signs, graph_transformer, sona)
                          |
                    [ WebSocket Broadcast ]
                          |
Browser <──WS:8765── [ Axum Server :8080 ] ──> Static UI files
Crate Role
wifi-densepose-wifiscan Multi-BSSID WiFi scanning (ADR-022)
wifi-densepose-core Shared types and traits
wifi-densepose-signal CSI signal processing algorithms
wifi-densepose-hardware ESP32 hardware interfaces
wifi-densepose-wasm Browser WASM bindings for the sensing UI
wifi-densepose-train Full training pipeline with ruvector
wifi-densepose-mat Disaster detection module

License

MIT OR Apache-2.0