Files
Rendezvous/docs/security/threat-model.md
T
2026-07-16 04:11:24 +02:00

7.2 KiB

Rendezvous v1 threat model

Tracking: #2

Scope and assets

This model covers the public HTTP API, public LiteNetLib-compatible UDP mediator, operator API, client SDK, game host integration, reverse proxy, secret provider, observability pipeline, and the proposed future shared store. Gameplay traffic after direct connection and game-owned identity/admission systems are outside the service boundary, but their handoff is in scope.

Assets include tenant isolation, service availability, signing and publisher keys, lease and connection credentials, raw endpoints, unlisted share codes, listing integrity, audit integrity, and the guarantee that Rendezvous does not turn into a reflector or private-network probe.

Actors and assumptions

  • Anonymous Internet attackers can send arbitrary HTTP and UDP traffic, spoof source addresses where their network permits it, scrape listings, and create many identities or addresses.
  • Malicious publishers possess credentials only for their assigned tenant and may submit hostile metadata or attempt to target arbitrary endpoints.
  • Malicious clients can obtain legitimate join credentials for sessions they can see and may replay, race, mutate, or share those credentials.
  • A compromised game client and its SDK are fully attacker-controlled. No reusable secret in them is trustworthy.
  • Operators are privileged but fallible. Their actions are authenticated, constrained, and audited.
  • The reverse proxy, secret provider, and build/release pipeline are trusted dependencies. Their compromise is considered and mitigated but cannot be completely contained by the application.

Abuse paths and controls

flowchart TD
    A["Attacker input"] --> H{"HTTP or UDP?"}
    H -->|HTTP| V["Authenticate when required; validate tenant, schema, size, and rate"]
    H -->|UDP| U["Parse bounded datagram; validate capability before response"]
    V --> S{"Allowed and in quota?"}
    U --> E{"Capability valid, fresh, scoped, unused, and endpoint observed?"}
    S -->|No| R["Stable bounded rejection"]
    E -->|No| D["Silent drop + bounded aggregate metric"]
    S -->|Yes| State["Atomic ephemeral state transition"]
    E -->|Yes| State
    State --> O["Allowlisted audit event; no secrets/endpoints"]
Threat Example Required prevention/detection Planned evidence
Spoofing and reflection Forged UDP source causes traffic to a victim No response before valid capability proof; send responses only to observed authenticated sources; at most two responses and <=2.0 verified byte amplification Packet-level spoof/reflection tests and amplification accounting
Private-network probing Publisher supplies 127.0.0.1, link-local, or another victim as a same-LAN candidate Accept only bounded private-unicast claims inside a scoped authenticated UDP contribution; reject prohibited ranges; disclose only to the opposite role in that attempt; bound SDK probes Endpoint classification matrix and three-party adverse tests
Capability/ticket replay Reuse a captured token to repeat introductions or connect Short expiry, role/tenant/attempt scope, atomic one-time consumption, bounded skew, key rotation Concurrent replay and post-expiry tests with golden vectors
Cross-tenant access Game A browses, renews, or joins Game B Server-derived principal scope on every lookup and atomic mutation; indistinguishable not-found response Tenant isolation tests across every endpoint/store operation
Listing spam and scraping Flood registrations or enumerate public sessions Trust-mode quotas, per-principal/address limits, bounded pages/cursors, rate limits, aggregate alerts Rate-limit, cursor-tamper, and sustained-load tests
Metadata injection Control characters or markup attack logs/UI UTF-8/schema/size validation; store as data; exclude values from audit; SDK does not render markup Malformed Unicode/JSON corpus and TestClient safe-display tests
Credential theft Secret appears in log, URL, metric, crash, or package Credentials in headers/bodies only; allowlisted logging; secret-provider indirection; no credential metric labels Log-capture tests, repository/package scans, rotation exercise
Parser/resource exhaustion Oversized, nested, fragmented, or high-rate input Fixed ceilings, bounded parsers/queues/concurrency, early rejection/drop, no input-sized logging Fuzz/property corpus, allocation limits, overload tests
Stale or crashed host Dead listing remains joinable Both lease and recent authenticated presence required; atomic expiry; join rechecks freshness Fake-clock lifecycle and join-race tests
Clock manipulation Token accepted outside intended lifetime Server-issued timestamps, monotonic elapsed-time for local expiry, <=30 s wall-clock skew Boundary and clock-jump tests
Operator misuse Unauthorized enumeration/revocation or secret exposure Separate strong auth/network policy, least privilege, tenant scope, immutable audit, secrets never readable through API Authorization matrix and audit completeness tests
Reverse-proxy confusion Forged forwarded address bypasses limits Trust forwarding headers only from allowlisted proxies; direct traffic uses socket peer Forwarded-header spoof tests
Store race Renew/revoke/expire/replay operations interleave Compare-and-swap/transactional interfaces and deterministic outcomes Parallel race tests with a fake clock
Dependency/supply-chain compromise Malicious or drifting package/build output Central pinning, lock files, reproducible builds, vulnerability review, signed release provenance Locked clean restore, dependency audit, artifact verification
Availability attack Valid-looking traffic fills CPU, memory, queues, logs Layered quotas, bounded queues/tasks, graceful overload, readiness/drain, capacity alerts Load/soak/resilience gates and forced saturation tests

Security invariants

The implementation and its tests must preserve these invariants:

  1. No UDP response is sent to an endpoint that has not presented a valid scoped capability from that observed endpoint.
  2. No browse response contains an endpoint, secret, internal attempt ID, or credential.
  3. Every state lookup and mutation includes server-derived game/environment scope; caller-supplied scope alone is never authoritative.
  4. A listing is visible and joinable only while both lease and presence are fresh at the atomic decision point.
  5. A capability or ticket can cause at most one successful state transition for its intended role and attempt.
  6. Join authorization never bypasses host-owned final admission.
  7. Input cannot create unbounded memory, work, response bytes, metric labels, or log volume.
  8. Raw endpoints and secrets never enter normal logs, traces, audit payloads, or metric dimensions.

Residual risk

Direct traversal cannot work through every NAT, firewall, carrier, or platform policy. Rate limiting cannot eliminate distributed abuse. A compromised trusted proxy, secret provider, operator identity, game grant issuer, or host credential can act within its granted scope until detected and revoked. Unlisted share codes can be disclosed by recipients. These risks are communicated as typed outcomes and operational signals rather than hidden behind a success claim.