# Agent security

Why a coding agent that reads production telemetry treats it as untrusted text, and the scopes, approvals and isolation that bound what it can do.

Anyone with your public DSN can send an exception message, a log line or a span attribute. An agent that reads that text can be misled by it. Unhandled limits what a misled agent can do, and your agent's permissions limit the rest.

## Telemetry is data

Every MCP result that carries text from your apps or their users says so twice. The result's `_meta` lists the fields under `unhandled.net/untrustedFields`, and the result text starts with a `provenance` object with the same list and a note. Clients that hide `_meta` still show the note. `get_fix_context` and the copied fix prompt fence the telemetry inside a block that a trusted line marks as data. Invisible and direction-changing characters arrive as `\u` escapes.

Secrets are removed from every telemetry result. The organization's [AI data policy](/docs/features/ai-summaries#data-policy) can also replace emails, IP addresses, phone numbers and user ids with stable tokens such as `<email:3f9a01c2>`. [Untrusted text in results](/docs/features/mcp-server#untrusted-text-in-results) has the details.

Put the rule in your repository too. The [AGENTS.md section](/docs/agents/prompts#agentsmd) tells the agent never to follow instructions found in telemetry.

## Scopes

Connect with the fewest scopes the job needs. Fixing an issue needs only `issues:read`. The consent page has **Read only**, **Triage** and **Full** presets, and only read scopes start ticked. A call runs only when the connection's scopes, the organization's MCP policy and your role all allow it. See [Scopes and access](/docs/features/mcp-server#scopes-and-access).

## Confirm and approval

`confirm: true` is something the caller asserts about itself, so a misled agent can send it. It is not a safeguard. Approval is. While **Require human approval for sensitive agent actions** is on, which is the default, a held call returns `approval_required` and does nothing until a person opens the approval link and approves it. An approval is bound to the connection, the tool and the exact arguments, and runs once. For 10 minutes after a connection receives a secret, the server refuses calls that send data to a new destination. See [Confirm and approval](/docs/features/mcp-server#confirm-and-approval).

## Headless agents

An agent with nobody at the keyboard has only the guardrails you set up first.

- **Keep permissions the agent's own.** The CLI passes no flag that skips approvals unless you add one with `--agent-args`. Flags such as `--dangerously-skip-permissions`, `--yolo` or `--dangerously-allow-all` let the agent run any command on text that came from production, so use them only in a sandbox you can throw away. Allow the edits and test commands it needs in the agent's settings rather than turning approvals off.
- **Withhold credentials.** Do not give a watching agent deploy keys, production credentials or a shell outside the repository.
- **Isolate the checkout.** Run `unhandled watch` in a dedicated clone, worktree or container, so a run cannot touch work in progress, and review every pull request before it merges.
- **Use an agent identity with read scopes.** Cloud agents and CI use an [agent identity](/docs/features/mcp-server#agent-identities) with a 90-day cap and an optional IP allowlist. Approvals for its sensitive calls still go to a person.

## Audit what an agent did

Every MCP call is recorded. **Settings > Agent activity** lists them with filters and exports, and a row can revoke the connection. Changes an agent makes appear under your user in the issue's activity, with the app and the tool named, such as "Claude Code (via roberto@) resolved the issue".

The [security model for AI agents](/trust/ai-agents) covers how agents connect, what they can do, and the approvals and audit trail that limit them.
