Repository navigation
Description
What happened
Security and stability hardening audit finding H06 / P2 (2026-09-28). Priority is an audit recommendation, not a claim of a production incident.
The device receiver caps concurrent connections at 8 with one shared counter. Direct TCP connections and Relay-attached streams both count against it. A slot is taken before TLS starts, and any connection over the cap is closed immediately.
An unauthenticated socket holds its slot for up to 8 s while the TLS handshake is pending. The server accepts TLS without a client certificate (CERT_OPTIONAL). After such a handshake, the connection gets one request, which waits up to 45 s. A client that can reach the direct port can therefore keep all 8 slots busy by reconnecting repeatedly, with no credentials at all.
Isolated fixture: a loopback receiver built from the existing relay test lab. A paired client's direct probe succeeded. After 8 idle TCP sockets were opened, the same probe failed at once with no_authenticated_route (0.0 s). It succeeded again after the sockets were closed. Relay attaches go through the same spawn/handle path, so they are refused in the same way while the cap is full.
What you expected
Unauthenticated sockets cannot lock out paired peers. Possible fixes:
- Keep separate pre-authentication and post-authentication budgets.
- Shorten the pre-TLS timeout.
- Wait less for cert-less connections than for authenticated ones.
- Add an optional per-source-IP limit.
Environment
- Baseline: published session-peer v1.0.2, commit
2046836822b88e53246de73851186598604cb5ec. - Reproduction: isolated loopback fixture on temporary stores; no live message/ACK tests or production mutation.
- Audit environment: macOS arm64, Python 3.14.7, with
websocketsandcryptographyinstalled in a throwaway virtualenv. - Discovery output: not applicable; no real session identifiers or credentials are included.
Source evidence
- session_peer_relay/app.py#L131-L134
- session_peer_relay/app.py#L156
- session_peer_relay/app.py#L189
- session_peer_relay/app.py#L206-L208
- session_peer_relay/wire.py#L20
- session_peer_relay/wire.py#L197
- session_peer_relay/wire.py#L239
- session_peer_relay/identity.py#L127
Acceptance criteria
- A fixture with at least 8 idle or slow-TLS sockets no longer stops a paired peer's direct probe or a Relay-attached request from getting through.
- Unauthenticated and cert-less connections have explicit, shorter timeouts, and tests cover them.
- Total resource use stays bounded, including file descriptors and tasks.
- Existing refusal and diagnostic semantics for authenticated peers are unchanged.
Scope and limitations
The attacker needs network reach to the direct listener (LAN or tailnet). The impact is denial of service only. No message content or authorization is exposed.
Target: v1.0.3. This issue does not authorize a release or operating-service changes.
Related: none. #163 covers Relay reconnect lifecycle, not the receiver connection cap.
Checked
- Searched existing issues for duplicates.
- Removed credentials, conversation contents, private paths and real device/session identifiers.
- Used isolated fixtures without weakening inbound permissions.
Activity