Skip to content

sensing-server: UDP CSI receiver binds 0.0.0.0 with no bind-address option, while HTTP defaults to 127.0.0.1 #1394

Description

@proffesor-for-testing

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

  • Add a UDP bind-address flag + env var mirroring SENSING_BIND_ADDR
  • Keep 0.0.0.0 as the default (changing it would break real deployments)
  • Consider an optional source-address allow-list
  • Note the exposure in the startup log, as the edge-registry fetch already does for its outbound dependency

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 sourceesp32. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity-related issues and hardening

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions