Security Notes
What Chat UI does to keep untrusted content from running or leaking, and what stays your job. The UI is a client: it shows what the server allows and refuses what it can, but every permission is enforced on the server.
The server decides
Hiding a button is not access control. Approvals, budget changes, feedback, rename, pin, bulk delete, export and file access are all checked by the server; the host's props and the agent's experience only decide what is offered. A refused action comes back with a code (403 action_disabled, budget_forbidden, action_forbidden, ...) and is shown localized. See Error codes.
Authentication
- Pass credentials with
authorization,headers, or, for a token that renews,getHeaders(called before every request). A long-lived secret key inauthorizationis visible to anyone who opens the page: fetch a short-lived token from your own server instead. - A custom
fetch(cookies, proxies) is used for every request, including uploads, file URLs and the follow stream. - An embedded chat never uses cookies: its session token is opaque, kept in memory only, sent as
Authorization: Bearerwithcredentials: "omit", renewed before it ends and revoked oncp:logout. See Embedding the Chat.
What the UI will not draw or follow
| Content | Rule |
|---|---|
| Assistant Markdown | Rendered without raw HTML; links open in a new tab with rel="noopener noreferrer" |
| Welcome, announcements, terms (portal-controlled Markdown) | Stricter renderer: no raw HTML, images checked; announcements allow only text, emphasis, code and links |
| Images | https:, blob:, relative or same-origin, http: only on an http page or from the page's own origin, and base64 PNG / JPEG / GIF / WebP. javascript: URLs, SVG data URLs and other schemes are dropped |
| Thumbnails and local previews | PNG, JPEG, GIF and WebP only; an SVG (which can carry script) is a file chip with a download |
| Stored files fetched with credentials | Kept as blobs with their own type only if they are raster pictures; anything else becomes an opaque download, so a stored HTML or SVG file never runs on your origin |
| File download links | http:, https:, blob: and relative addresses (checked the way the browser's URL parser reads them, so java\nscript: is rejected); a data: URL has no Download link |
| Legal links | Plain web addresses, a path of the page, and mailto: for support; everything else is dropped |
| Welcome and terms pictures | https: (optionally restricted to welcomeImageHosts / allowedImageHosts), a path of the page, or a raster data URL |
If you draw images or links yourself (renderImage, your own message list), keep the same rules: safeImageSrc and safeFileHref are exported.
Deep links and the composer
initialInput only fills the composer. autoSend sends it without a click, so never forward an arbitrary query string to it: let your server decide whether a link may auto-send. autoSend never sends into a conversation opened with conversationId.
Host tools and context (embedded chat)
- The arguments of a host-page tool call were written by the model: validate types and ranges, never build code or queries from them, and ask the person first (a
tool_approval) for anything that changes state. The chat validates them against the declaredinputSchemaand applies a timeout (60 s default, 600 s at most), but it cannot know what your handler does. cp:contextis the host page's own claim about itself, sent asmetadata.uiContextwithuiContextUntrusted: true. Use the signed claim in the token for authorization.eventContent="text"copies message text intopostMessageevents (4000 characters at most). Keep it at"none"unless the host needs the text, and checkevent.originandevent.sourceon the host side.
Browser storage
Chat UI keeps no conversation or token in the browser unless you ask: only cp:announcement:dismissed:<id> and cp:notify:prefs (when those features are on) and, with LocalStorageThreadStore, the threads of a stateless transport. Every access is guarded, so blocked storage only means choices last for the page view. Do not use LocalStorageThreadStore for sensitive conversations on shared machines.
Content security policy
- Allow the origin of your chat API and, if you use it, the file route, in
connect-src; allowblob:inimg-src(pictures of stored files are shown from blob URLs when they need credentials) anddata:for inline raster images. - The built-in notification sound uses the Web Audio API and needs no media files.
- For an embed, the server must send
frame-ancestorsfor the allowed origins only; the iframe also refuses to start unless the declared origin is allowed and is the embedding page.
Error text
Server error messages are shown as written when the code has no localized string, and the server's own wording is kept on error.serverMessage. Do not put secrets in error messages on the server, and avoid forwarding serverMessage to a third-party logger without redaction.
Related
- Embedding the Chat
- File Uploads
- Defaults and limits
- Authentication (the server side)

