Summary
wifi-densepose-sensing-server lets an operator bind the HTTP API to a chosen address (--bind-addr / SENSING_BIND_ADDR, default 127.0.0.1), but the UDP CSI receiver binds 0.0.0.0 unconditionally, with no equivalent flag. An operator who has deliberately kept the API on loopback still has a CSI ingest port open on every interface.
Why now
Not a newly-introduced bug and not an alarm — unauthenticated CSI datagrams are a documented design position for the data plane (ESP32 nodes are data-plane sensors, not attested mesh members). This is narrower: the two listeners disagree about what "localhost only" means, and only one of them is configurable.
Done looks like
- The UDP receiver accepts a bind address the same way the HTTP listener does, defaulting to today's behaviour so nothing changes for existing deployments.
- Optionally, a peer allow-list so a hub can accept frames only from its paired nodes.
--help makes the exposure explicit either way.
Work items
Technical detail
v2/crates/wifi-densepose-sensing-server/src/main.rs:
- HTTP:
#[arg(long, default_value = "127.0.0.1", env = "SENSING_BIND_ADDR")]
- UDP (
udp_receiver_task): let addr = format!("0.0.0.0:{udp_port}"); — hardcoded, port configurable, address not.
recv_from passes the datagram straight to parse_esp32_frame; the sender address is discarded (_). There is no PSK, HMAC, allow-list or replay protection on the CSI path — grep for psk|shared_secret|hmac across the crate's src/ returns nothing.
Interaction with the #1004 source state machine
In auto mode the receiver is always bound, and the first real frame promotes source → esp32. That behaviour is correct and was fixed deliberately (a one-shot boot probe used to latch simulate forever). The side effect is that anything able to reach the port can also flip a server out of simulate mode into presenting injected frames as live sensor data.
Scope of impact
- Bundled desktop install (ADR-055) — server is a child process, traffic is loopback. The open UDP port is the only part of that topology not actually restricted to loopback.
- LAN / hub deployment — the intended path is a direct link to a paired Seed or V0 device. The pairing credential exists (
seed_token bearer, ADR-066, plus a device-id-bound PSK for the V0 /edge swarm endpoints), but it is not applied to the UDP data plane.
Deliberately out of scope
Authenticating the CSI datagrams themselves (per-node HMAC, DTLS) is a device-plane design change spanning firmware and consumers. This issue is only about making the listener as configurable as its HTTP sibling.
Related, unrelated to this fix: the mapping between the V0 /edge PSK and provision.py --seed-token is documented as an open gap elsewhere.
Summary
wifi-densepose-sensing-serverlets an operator bind the HTTP API to a chosen address (--bind-addr/SENSING_BIND_ADDR, default127.0.0.1), but the UDP CSI receiver binds0.0.0.0unconditionally, with no equivalent flag. An operator who has deliberately kept the API on loopback still has a CSI ingest port open on every interface.Why now
Not a newly-introduced bug and not an alarm — unauthenticated CSI datagrams are a documented design position for the data plane (ESP32 nodes are data-plane sensors, not attested mesh members). This is narrower: the two listeners disagree about what "localhost only" means, and only one of them is configurable.
Done looks like
--helpmakes the exposure explicit either way.Work items
SENSING_BIND_ADDR0.0.0.0as the default (changing it would break real deployments)Technical detail
v2/crates/wifi-densepose-sensing-server/src/main.rs:#[arg(long, default_value = "127.0.0.1", env = "SENSING_BIND_ADDR")]udp_receiver_task):let addr = format!("0.0.0.0:{udp_port}");— hardcoded, port configurable, address not.recv_frompasses the datagram straight toparse_esp32_frame; the sender address is discarded (_). There is no PSK, HMAC, allow-list or replay protection on the CSI path — grep forpsk|shared_secret|hmacacross the crate'ssrc/returns nothing.Interaction with the
#1004source state machineIn
automode the receiver is always bound, and the first real frame promotessource→esp32. That behaviour is correct and was fixed deliberately (a one-shot boot probe used to latchsimulateforever). The side effect is that anything able to reach the port can also flip a server out of simulate mode into presenting injected frames as live sensor data.Scope of impact
seed_tokenbearer, ADR-066, plus a device-id-bound PSK for the V0/edgeswarm endpoints), but it is not applied to the UDP data plane.Deliberately out of scope
Authenticating the CSI datagrams themselves (per-node HMAC, DTLS) is a device-plane design change spanning firmware and consumers. This issue is only about making the listener as configurable as its HTTP sibling.
Related, unrelated to this fix: the mapping between the V0
/edgePSK andprovision.py --seed-tokenis documented as an open gap elsewhere.