C1 Identity & least privilege
Minimal 0.00 / 1.00
AI SDK UI has no notion of who is asking. The documented chat route reads whatever message history the browser posts and runs the developer's server-side tools with the server process's own credentials (provider API keys from environment variables, plus whatever the tools hold), with no per-request authorization hook in the UI layer. Because the client supplies the whole history, a caller can also fabricate an assistant tool call with a matching approval and have the server execute any registered tool with inputs of its choosing, unless the developer opts into approval signing. Every tool therefore runs with the server's full authority on behalf of any caller who can reach the route.
C2 Approval gates
Minimal 0.38 / 1.00
A real per-call approval flow exists: the server can mark tools as needing user approval (statically, per tool, or by a function of the input), the browser receives the exact tool input in an approval-requested state, and denials are first-class. The server re-validates approved inputs against the tool schema and can verify an HMAC signature that binds the approval to the exact call. But approval is off by default: unless the developer configures it, every tool the model calls executes immediately. Signature checking is a separate experimental opt-in; without it, approvals are just fields in the client-posted history and a modified client can fabricate them. Client-side tools run in the browser through developer callbacks with no SDK gate.
C3 Tool & action scoping
Moderate 0.53 / 1.00
Every tool call the model makes is parsed against the tool's declared input schema before execution, unknown tool names are rejected, and approvals replayed from client history are re-validated against the schema. That is typed validation, not allowlisting: the framework has no path, URL or quantity checks of its own, and what a tool can do is whatever the developer's execute function does. The developer chooses the tool set and can narrow it per step with activeTools.
C4 Code-execution isolation
N/A · full credit 1.00 / 1.00
Nothing in the scoped code interprets model output as code: the hooks, the UI message stream and streamText contain no shell, eval or interpreter. streamText accepts an experimental sandbox handle but only passes it through to developer tools; sandbox packages are separate and outside this scope. Developers who add code-running tools get no isolation from AI SDK UI.
C5 Untrusted input blast radius
Minimal 0.00 / 1.00
Tool results, MCP tool output and any fetched content enter the model's context as ordinary tool messages with nothing marking them as untrusted, and nothing in the framework changes what the model may do after reading them. With approval off by default, an injected instruction can drive any registered tool, including ones that send data out. The one structural help is that client-posted system-role messages are rejected by default. The MCP App bridge can forward app-originated chat messages to the host if the developer wires that handler.
C6 Memory, context & configuration integrity
Minimal 0.25 / 1.00
The UI layer keeps no memory store of its own, but its core loop re-injects the whole client-held conversation, including past tool results, into the model every turn, and the documented persistence pattern saves that history server-side for later sessions. The server trusts that history: assistant turns, tool results and approvals in it are taken as genuine unless the developer opts into approval signing or validateUIMessages. One real guard: system-role messages posted by the client are rejected by default. The persistence guide keys chats by a client-supplied id and explicitly leaves authorization out.
C7 Third-party extensions
Minimal 0.35 / 1.00
The default chat setup loads no third-party code. @ai-sdk/react does export an experimental MCP App renderer that runs HTML supplied by an MCP server inside a double iframe; the inner frame has no same-origin access, tool calls from the app are denied unless the host allow-lists them, and device permissions are deny-by-default. The HTML is whatever the server serves at render time, with no pinning or integrity check, and a restrictive content security policy is only built when the server itself supplies CSP metadata. Enforcement of the inner sandbox depends on the developer-hosted proxy page.
C8 Secrets & sensitive-data protection
Minimal 0.45 / 1.00
Provider API keys stay on the server and never go to the browser in the documented setup. Errors from local tools and the stream are masked to a generic message before reaching the client by default, telemetry sends nothing unless an integration is registered, and per-request context values are excluded from telemetry unless explicitly included. There is no redaction of what goes to the model provider, and the provider keys are long-lived environment variables.
C9 Audit & traceability
Minimal 0.35 / 1.00
The framework emits structured lifecycle events, including the start and end of every tool execution, to telemetry integrations and callbacks, and the browser holds a structured record of each call in the message parts. None of it is kept by default: no integration is registered, so nothing is recorded server-side unless the developer adds one. Approvals and denials are not separate audit events, and client-side tool runs are only seen by the server as results in the next request.
C10 Limits & kill switch
Minimal 0.30 / 1.00
Each server request runs one model step by default, which keeps a single request small. But the multi-step loop in AI SDK UI runs from the browser: with sendAutomaticallyWhen set, as the docs recommend for tools and approvals, the client resubmits after every completed tool round with no cap. Timeouts and token limits are opt-in. The stop() helper aborts the browser request, but the server keeps running the model call and any in-flight tool unless the developer forwards the request's abort signal, which the default route does not.