diff --git a/docs/gateway/protocol.md b/docs/gateway/protocol.md index c3d712073ec..964b510d626 100644 --- a/docs/gateway/protocol.md +++ b/docs/gateway/protocol.md @@ -240,6 +240,17 @@ The Gateway treats these as **claims** and enforces server-side allowlists. - Presence entries include `deviceId`, `roles`, and `scopes` so UIs can show a single row per device even when it connects as both **operator** and **node**. +## Broadcast event scoping + +Server-pushed WebSocket broadcast events are scope-gated so that pairing-scoped or node-only sessions do not passively receive session content. + +- **Chat, agent, and tool-result frames** (including streamed `agent` events and tool call results) require at least `operator.read`. Sessions without `operator.read` skip these frames entirely. +- **Plugin-defined `plugin.*` broadcasts** are gated to `operator.write` or `operator.admin`, depending on how the plugin registered them. +- **Status and transport events** (`heartbeat`, `presence`, `tick`, connect/disconnect lifecycle, etc.) remain unrestricted so transport health stays observable to every authenticated session. +- **Unknown broadcast event families** are scope-gated by default (fail-closed) unless a registered handler explicitly relaxes them. + +Each client connection keeps its own per-client sequence number so broadcasts preserve monotonic ordering on that socket even when different clients see different scope-filtered subsets of the event stream. + ## Common RPC method families This page is not a generated full dump, but the public WS surface is broader diff --git a/docs/web/control-ui.md b/docs/web/control-ui.md index dd9c2923803..90f38540a86 100644 --- a/docs/web/control-ui.md +++ b/docs/web/control-ui.md @@ -278,6 +278,18 @@ Trusted-proxy note: See [Tailscale](/gateway/tailscale) for HTTPS setup guidance. +## Content Security Policy + +The Control UI ships with a tight `img-src` policy: only **same-origin** assets and `data:` URLs are allowed. Remote `http(s)` and protocol-relative image URLs are rejected by the browser and do not issue network fetches. + +What this means in practice: + +- Avatars and images served under relative paths (for example `/avatars/`) still render. +- Inline `data:image/...` URLs still render (useful for in-protocol payloads). +- Remote avatar URLs emitted by channel metadata are stripped at the Control UI's avatar helpers and replaced with the built-in logo/badge, so a compromised or malicious channel cannot force arbitrary remote image fetches from an operator browser. + +You do not need to change anything to get this behavior — it is always on and not configurable. + ## Building the UI The Gateway serves static files from `dist/control-ui`. Build them with: