Turns the review's code-implementable P0/P1 items into ADRs: source provenance state machine (synthetic never presents as live), UDP data-plane bind hardening (loopback default + allowlist, step one), multi-node semantic correctness (per-node inference, node-keyed rate limiter, stale state), model release sanity gates (block degenerate/mislabeled heads), and CSI data-incident repo controls. Also fixes the stale .gitignore rule so the active recordings directories and CSI globs are covered going forward. Tree removal of existing recordings, history rewrite, and withdrawal of the published presence head are gated on maintainer sign-off (outward-facing / destructive) and intentionally not done here. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_015TcKegTS7QqhWPC2L2SzaS
2.6 KiB
ADR-293: Sensor data-plane hardening — UDP bind control and source allowlist (step one)
- Status: Accepted — initial implementation (this PR)
- Date: 2026-08-11
- Deciders: ruv
- Tags: security, udp, sensor-ingest, sensing-server
Context
The CSI UDP receiver binds 0.0.0.0:{udp_port} unconditionally
(main.rs:5706), with no equivalent of the HTTP --bind-addr flag (which
correctly defaults to 127.0.0.1), no source allowlist, no message
authentication, no device identity, and no replay defense. Any host that can
reach the UDP port can inject a valid-shaped frame, flip an auto-detecting
server into a live source state, and influence presence/vital/automation
outputs (issue 1394).
An IP allowlist does not stop LAN spoofing, but bind control plus an allowlist is the correct, shippable first step; per-device keys + authenticated encryption + monotonic sequence + freshness window + replay rejection is the full fix and is larger.
Decision
This PR (step one):
- Add
--udp-bind(envRUVIEW_UDP_BIND), defaulting to127.0.0.1. Binding to a routable address is now an explicit operator choice, mirroring the HTTP path. Desktop/appliance defaults stay loopback. - Add an optional source IP/CIDR allowlist (
--udp-allow); when set, frames from other sources are dropped and counted. Loopback is always allowed. - Emit a startup security log line stating the bind scope and whether an
allowlist is active; refuse a routable bind without an allowlist unless an
explicit
--udp-insecure-lanoverride is passed (parallel to the existing Docker HTTP refusal). - Publish a
SECURITY.md/advisory note describing the threat model and safe deployment.
Explicitly deferred to a follow-up ADR (step two): per-device provisioned keys, MAC/AEAD, device identifiers, monotonic sequence numbers, freshness window, and replay rejection. This ADR documents that gap rather than implying the data plane is authenticated.
Consequences
- Removes the default open-to-LAN exposure with a one-line-safe default.
- Not spoof-proof on a trusted LAN — the advisory says so plainly, and the
override name (
--udp-insecure-lan) makes the residual risk legible. - A behavior change for anyone relying on the old implicit
0.0.0.0default; called out in the changelog and the startup log.
Validation
- Unit tests: default bind is loopback; routable bind without allowlist is refused unless overridden; allowlist accept/drop with counting; loopback always allowed.
cargo test -p wifi-densepose-sensing-server.- Real-silicon validation of the LAN path remains required before any deployment claim.