Nodus
Reference

Local endpoint security

Trust boundary, secret lifetimes, and threat model for the node's LAN listener.

Scope

Security properties of the Storage Node's local HTTP listener and the first-time pairing handshake. This listener is not the confidentiality boundary for file data — bulk data flows over WebRTC (DTLS). It is the trust boundary for identity and pairing on the LAN.

Secrets and their lifetimes

Challenge nonces (device ↔ node, local)

  • Generated by POST /nodus/challenge on the node.
  • 32 cryptographically random bytes.
  • TTL: 30 seconds — expired nonces are rejected.
  • Single-use: consuming a nonce on /nodus/auth removes it. A second use of the same nonce fails. Poisons (unknown nonces) are rejected without side effects.
  • Stored in node memory (not disk), keyed by hex nonce.

Pairing tokens (Relay-issued)

  • Issued by POST /pairing/sessions (authenticated) on the Relay.
  • TTL: 15 minutes (expires_at on the row).
  • Single-use: the first consumer atomically sets consumed_at (UPDATE ... WHERE consumed_at IS NULL). Any later use is rejected.
  • Device-bound: the token is bound to the requesting device's Ed25519 public key at issuance. The node verifies the pairing signature/auth identity corresponds to the device the token names; a stolen token cannot be redeemed by a different device unless that device also has the token and the correct identity.
  • Verified twice: once by the node (local pairing_sessions) and once by the Relay (/pairing/sessions/verify), whichever path is hit. The Relay row is the source of truth for single-use across re-syncs.

Node bootstrap pairing codes (Relay, Phase 7b)

Separate from the device↔node tokens above: first-time Storage Node association uses a one-time NODUS-XXXX-XXXX pairing code redeemed over the public origin via POST /pairing/codes/redeem. The code is hashed at rest, single-use, TTL-bounded, IP rate-limited, and never substitutes for the node's Ed25519 WS challenge-response. See bootstrap-pairing.md for the endpoints, failure reasons, and threat model.

Threat model

ThreatMitigation
Rogue LAN device impersonates a nodeNode proves identity via Ed25519 challenge-response; a rogue device cannot sign nonces with the node's private key
Spoofed mDNS advertisementDiscovery is not authentication. Pairing binds to the account (Relay-issued token), not to whatever answers on the LAN. The client verifies the node's public key against the node_id in the pairing URL
Replayed pairing tokenSingle-use token, redeemed atomically at the Relay; server-side consumed_at
Sniffed token used by a different deviceToken is bound to a device pubkey at issuance; redemption requires that same device identity
Replayed challenge-responseNonces are single-use and TTL-bounded
On-path attacker swaps WebRTC SDP/ICE on the plaintext LAN listenerEach signaling request signs "{device_id}:{session_id}:{timestamp_ms}:{blake3(payload)}", so a body swap invalidates the signature
Browser origin probing the nodePermissive CORS on the LAN listener, accepted for the home-LAN v1 trust model

Known accepted risks (v1)

  • Plaintext HTTP on the local link: handshake bytes could be observed on the LAN. Pairing-intent replay is blocked by single-use + device binding; node impersonation is blocked by the signature protocol. Not transport-encrypted for v1 — revisit TLS if untrusted-LAN scenarios become in-scope.
  • A compromised device that was paired retains its local trust until revoked (same accepted tradeoff as ADR-0001).

Offline pairing limitation

First-time pairing while the node is fully offline (no local token record and no connectivity to the Relay for verification) is not supported. The client sees a "node unreachable" error. Pairing requires the node to have either received the Relay's WS push or be able to reach the Relay's verify endpoint.

On this page