How the Control UI restricts the browser and authenticates its own routes.

Content security policy

The Control UI allows same-origin assets, data: URLs, locally generated blob: URLs, and remote HTTPS images. Remote HTTP images are blocked. Protocol-relative image URLs follow the document's scheme.

In practice:

Page metadata reads stop at the end of the HTML head or after 64 KiB, whichever comes first; metadata beyond that limit is omitted. The Gateway streams the head without building a page DOM. Anonymous previews use a bounded cache per requesting principal and runtime config revision for one hour when available, or five minutes when unavailable; URL fragments share the same entry. Repeated links share pending requests, and a page that declares the same social image and favicon downloads it once. The 15-second preview deadline includes queue wait, fetching, and image work. Disabling automatic favicons or retiring the request's authority suppresses cached previews too.

The browser-side CSP restriction itself is always on and not configurable.

Public transcript boundary

Public threads use the same /chat/... URL as the authenticated Control UI. Anonymous readers receive a separate, read-only document, never an operator connection. Log in goes through a protected same-origin handoff and returns to that thread with the person's existing permissions. Identity headers on the anonymous thread path do not authorize private access. Private and missing threads have the same anonymous unavailable response.

In token/password deployments, the reader can recognize a browser-held session token or paired-device credential scoped to the current Gateway address and base path. After the protected probe returns 401, that presence is only a navigation hint to open the app shell; the reader never sends the credential or authorizes session data. The app's existing WebSocket and bootstrap checks still apply. A 204 probe continues into the app, while 403 keeps the public reader even when local credentials exist. Trusted-proxy and external-login handoffs retain their existing authentication and permission checks.

Loopback HTTP retains its public-reader support. On non-secure ingress where publication is unavailable, token/password chat links serve the app shell directly, without looking up or disclosing a transcript. Serving the shell grants no Gateway or session access.

The public renderer includes only user messages and assistant final-answer text. It omits tools, reasoning, files, images, widgets, hidden messages, and internal metadata, and applies best-effort credential-pattern redaction. A restrictive content security policy permits only the fixed reader script; transcript HTML cannot execute. Responses retain Cache-Control: no-store and Referrer-Policy: no-referrer. Server-side representation reuse never substitutes for a current publication check, including before a 304 response.

Anyone who knows a public thread URL can read its existing and future published text until the creator or a Gateway admin disables access. Re-enabling access revives the normal thread URL, but not previously revoked token links.

A login proxy must expose only the public thread documents and share namespace. Keep the session-entry login handoff, WebSocket, bootstrap, API, media, dashboard, and other application routes protected. The detailed deployment and revocation contract is in Public session transcripts.

Avatar route auth

When gateway auth is configured, the Control UI avatar endpoint requires the same gateway token as the rest of the API:

If you disable gateway auth (not recommended on shared hosts), the avatar route also becomes unauthenticated, in line with the rest of the gateway.

Concurrent profile-photo requests can share a Gravatar lookup. Each HTTP request keeps its own timeout and disconnect lifecycle, so one expired or disconnected request does not interrupt another client loading the same photo.

Saved profile photos use a bounded in-memory cache tied to the Gateway's profile catalog. Committed profile edits and merges invalidate cached representations; authentication still runs before cached responses and 304 Not Modified. Cold photo reads have a separate concurrency budget to preserve shared-state read capacity. During overload, the endpoint returns 503 Service Unavailable with Retry-After: 1 instead of a permanent lookup failure.

Assistant media route auth

Local image previews follow the chat's filesystem permissions. Project chats use their session workspace, including managed worktrees. Full Access, or disabled workspace-only filesystem protection, also permits image previews outside that workspace. An explicit session permission mode takes precedence over the agent's filesystem setting.

Assistant MEDIA: attachments in local project chats resolve relative paths inside the session workspace, including managed worktrees. Absolute paths in that workspace are staged for delivery under the same file-access checks. Selecting a project does not grant access to sibling worktrees.

Trusted audio attachments use the same session workspace boundary during playback. Mixed replies retain a separate failure card for each rejected attachment alongside successfully delivered media.

Attachment staging and trusted audio retain the requesting sender's read restrictions. Pending reads and copies stop when the source session's permission mode, workspace, or execution placement changes, or the turn is canceled. Rejected staged files are cleaned up before delivery.

Sessions dispatched to a cloud worker cannot read Gateway-local file paths, even with Full Access. Dispatch also revokes pending local previews and downloads. Gateway-owned inbound uploads remain available.

Full Access also preserves playback and downloads for existing attachments in the agent's configured workspace. It does not permit arbitrary outside non-image files.

With workspace protection enabled, an outside image shows Outside allowed folders. Hover over its filename to inspect the source path. Administrators can select Allow image to preview that exact file without changing the session's permissions or allowing its parent folder. The allowance uses a short-lived media ticket; replacing the file or restarting the Gateway requires a new allowance.

When gateway auth is configured, assistant local-media previews use a two-step route:

Tickets remain bound to the issuing reader's current access. Losing session visibility or role permissions stops new reads through existing tickets, even before they expire.

This keeps media rendering compatible with browser-native media elements without putting reusable gateway credentials in visible media URLs.

Uploaded and local chat image previews rendered with native image elements keep an already-loaded image visible during temporary connection or metadata-renewal failures. That failure tolerance applies only to the mounted image; it does not extend its media ticket or authorize fresh reads. Scrolling can reuse a successfully decoded image from the bounded in-memory preview cache while its existing metadata and ticket remain valid, without another image download or loading placeholder. An explicit missing or access-denied response, or a change to the source, credentials, or access scope, clears the retained image. When the UI receives a sharing invalidation, a role-configuration change, or the connection close for a role reassignment, cached previews must pass fresh admission before remounting.

Uploaded images also stay visible while a new session's workspace or worktree details arrive. Media access is rechecked in the background without replacing the loaded preview with a loading card.

Generated images under /api/chat/media/outgoing/... use the same capability principle through artifacts.download. The authenticated WebSocket request authorizes the transcript artifact and returns a short-lived URL. The HTTP media route rechecks that the artifact still belongs to the transcript before serving bytes. The previous shared-owner bearer path remains available for older Control UI clients during the compatibility window.

Approval links

Operator approval notifications can deep-link to a standalone approval document. The URL is stable for the lifetime of the approval and safe to forward between your own devices: it identifies the approval, never authorizes it.