---
title: "AI agent security: what a signed-in agent never gets"
description: "How to limit an AI agent that works in a signed-in browser: the 3 prompt kinds it never answers, server-side limits instead of prompt rules, and keys kept out."
canonical: "https://scalebrowser.net/blog/ai-agent-security"
last_modified: "2026-10-23"
published: "2026-10-23"
author: "davide"
category: "security"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://scalebrowser.net/llms.txt
> Use this file to discover all available pages before exploring further.

# AI agent security: what a signed-in agent never gets

> How to limit an AI agent that works in a signed-in browser: the 3 prompt kinds it never answers, server-side limits instead of prompt rules, and keys kept out.

An agent that works in your own browser profile is signed in to whatever that profile is signed in to: the mailbox, the shop account, the admin panel. Every page it reads can carry text written for the model rather than for you. The useful question is not whether the model can be fooled, because the vendors who test for it say it can, but what the browser lets a fooled agent do.

## What does AI agent security mean in a browser?

AI agent security in a browser means limiting what an agent can do with the sessions of the profile it drives, on the assumption that the model will sometimes follow text it should have ignored. Brave's security team put the objection in one sentence after an agentic browser was talked into taking over its own user's account:

<Quote attribution="Artem Chaikin and Shivan Kaul Sahib, Brave, August 2025">When an AI assistant follows malicious instructions from untrusted webpage content, traditional protections such as same-origin policy (SOP) or cross-origin resource sharing (CORS) are all effectively useless.</Quote>

The web's own boundaries separate one site from another. An agent reads every site with the same model, so text on one site can steer what it does on the next. Anthropic measured how often that happens with its own browser agent and published the numbers when it piloted [Claude in Chrome](https://claude.com/blog/claude-for-chrome) on 25 August 2025:

| Anthropic red-team test, August 2025 | Attack success rate |
| --- | --- |
| 123 test cases in 29 scenarios, without the new safety mitigations | 23.6 % |
| Same set, with the mitigations | 11.2 % |
| Browser-specific challenge set (hidden form fields, URL text, tab titles) | 35.7 % before, 0 % after |

An 11.2 % success rate is roughly 1 attack in 9. [Simon Willison](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/), writing about filters that claim to catch "95% of attacks", answered that "in web application security 95% is very much a failing grade". The limits that hold are the ones a sentence on a page cannot reach.

![Two pairs of bars for the attack success rate in Anthropic's red-team test of August 2025: 23.6 percent without and 11.2 percent with the mitigations over 123 cases in 29 scenarios, the latter in blue, and 35.7 percent against 0 percent on the browser-specific set.](/blog/ai-agent-security/injection-rate.png "Defences inside the model cut the success rate of injection attacks from 23.6 to 11.2 percent across 123 test cases, and on the browser-specific set from 35.7 to 0 percent.")

## Which 3 permissions does the agent never get?

The agent never decides 3 of the 14 kinds of prompt a browser draws beside the page: file system access, automatic downloads and payment. Scalebrowser reports every one of the 14 kinds to the agent, and these three are answered by the operator's rule before the agent is asked.

1. **File system access.** A yes gives the page a folder on your disk that it can read and write from then on.
2. **Automatic downloads.** A yes lets the site put further files on the disk without another click.
3. **Payment.** A yes spends money.

These are not the prompts that sound most invasive. Camera and microphone stay with the agent, because on a profile without a window no device sits behind them. The three locked kinds are the ones where a wrong answer costs something outside the browser. The operator can change any of the 14 rows, globally or per profile, and a standing rule an agent writes cannot widen what the operator locked.

A lock only works if the prompt is seen at all, because a prompt the browser draws outside the page is invisible to an agent that reads the page. We fired every trigger on [permission.site](https://permission.site/) against a release build of our engine and compared what was reported with what the page itself said.

<Evidence source="Scalebrowser permission bench, permission.site, 39 triggers, release build of our engine, 11 August 2026">

| Result per trigger | Triggers |
| --- | --- |
| Seen: reported to the agent while the page was still waiting | 13 |
| Silent: the page had its answer without any prompt holding | 23 |
| Blind: the page waited and nothing was reported | 0 |
| Unclear: the page sets no status for this trigger | 3 |

</Evidence>

Seeing is half of it, so the answer was measured separately. On 12 August 2026 four kinds (location, screen capture, a USB device chooser and idle detection) were answered through the agent's own tools on a fresh profile, and each answer was applied with nothing left pending.

## How does a server-side limit differ from a prompt rule?

A server-side limit is enforced by the program that executes the tool call, so no text the model reads can lift it; a prompt rule is a sentence the model weighs against the sentences on the page. Brave's [Comet disclosure](https://brave.com/blog/comet-prompt-injection/) shows what the second kind is worth. Instructions hidden behind a spoiler tag in a Reddit comment made the agent read the user's email address from the account page, fetch a one-time code from the signed-in Gmail and post both back as a reply. An agent that finds and reads threads for [our Reddit marketing plan](/blog/reddit-marketing) meets comments like that one, and in the plan a person posts every reply.

| Limit | Enforced by | Can text on a page lift it? |
| --- | --- | --- |
| "Never buy anything" in the system prompt | the model | yes, it competes with the page |
| Payment prompt locked | the daemon, before the agent is asked | no |
| Read-only mode | the daemon, on every call | no |
| No DevTools socket, no JavaScript, no private addresses | the daemon: the path does not exist over MCP | no |
| Stored password typed into the form | the daemon, after checking the frame | no |

The difference matters because of what sits behind the agent. In [an agent's own browser](/blog/ai-agent-browser) the profile stays signed in for weeks, so one fooled step can act with every account the profile holds. The [MCP server documentation](/docs/agents/mcp-server) lists the boundaries that are structural rather than configured: no CDP endpoint, no raw HTML, no cookies or headers, no file paths, and an address check that refuses loopback, private ranges and the cloud metadata address twice, once on the address and once on every IP the name resolves to. What a page can still probe on the local network from the browser itself is covered in Local Network Access in Chrome.

Read-only mode removes every tool that changes something from the listing and refuses it if it is called anyway, because a client that cached an older listing could still send the name. It removes `lease_profile` too, so an agent under it cannot start a browser of its own. The [tool reference](/docs/agents/tools#what-read-only-mode-leaves) lists the tools that stay. How the connection and its token are secured is covered in MCP security for browser agents.

What a server-side limit does not cover is the page itself. The server has no confirmation step before a click, and its documentation says so: it does not know that "Delete account" is irreversible. The [OWASP AI Agent Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html) asks to "Require explicit approval for high-impact or irreversible actions"; the payment lock is that approval for money, and for everything else the answer is a smaller tool set and a trail you read. Every call on a profile leaves one step in the [run trail](/docs/agents/runs), without its arguments, and a run can open with one sentence of intent so a person can see what the agent was trying to do.

### How do API keys stay out of the model's context?

API keys stay out of the model's context when the agent never receives them. Scalebrowser's daemon replaces a recognised value with a placeholder such as `{{sb:9f3c1a:npmjs.com/token}}` and types the real value itself, by default only into a matching field on the site the value is bound to. A reply the filter could not check is withheld rather than sent, and exactly one tool, `credential_store`, takes a secret as an argument, for a login the agent already holds. How the filter tells a real key from a random-looking class name is the subject of [API keys in the model context](/blog/llm-secrets); the rules are in the [secrets documentation](/docs/secrets). What the session cookies of a profile give an agent is covered in session cookies for AI agents.

<ProductMention />

## What should you set up before an agent gets your sessions?

Set up the limits before the first run, because each of them is set on the daemon's side and none can be changed by a tool call.

1. **Serve the smallest tool set.** `core` alone is 21 tools. `management` can delete profiles, and deleting a profile deletes every login inside it.
2. **Use read-only mode for agents that only watch.** It is the one built-in restraint on what a connected agent may do.
3. **Keep the three prompt locks.** Lift one per profile, not globally, when a task really needs it.
4. **Store logins instead of pasting them.** The agent names the fields and the daemon types the values, as the [credentials page](/docs/credentials) describes.
5. **Give each account its own profile.** A fooled step then reaches one identity, not all of them.

These limits decide what a fooled agent can do. How a page gets its instructions into the agent in the first place, and why filtering the text cannot close that door, is covered in prompt injection in a browser agent.
