Skip to content

15 min read

Inherited browser sessions

On this page

Authority is what an agent's actions are performed as: which identity the target system sees, which sessions are already established, and what those sessions are entitled to do. Capability is what the agent can express — the verbs available to it. The two come apart badly, and design reviews weigh the second because it is the one written in the proposal.

This chapter compares two designs that arrive in the same architecture forum and rank in opposite orders under the two measures. One is a Python execution tool in an ephemeral sandbox with nothing mounted and no egress except a write-only results bucket, contained as the previous chapter describes. The other is a computer-use agent driving Chrome on an operations analyst's own laptop, in the analyst's own profile, so that it can work through the supplier portals and internal tools the analyst already has open. The first can run arbitrary code and reaches nothing. The second cannot run anything and reaches everything the analyst can reach.

The two measures combine as a product rather than a sum, and that is why ranking on one of them alone goes wrong in both directions at once. What an incident costs depends on two quantities together: the set of verbs available to the agent, and the set of things those verbs are entitled to touch. A verb with nothing behind it does nothing — arbitrary Python against an empty filesystem with no route out produces heat and a log line. A narrow verb with everything behind it does a great deal, because a click is only a click until the thing being clicked is an approval control in a ledger. Multiplication is the right operation here for a specific reason: a zero in either factor takes the whole product to zero, and no size of the other factor rescues it. Reviews weigh capability because capability is the thing a proposal is written in. Authority is not in the document, and it is the factor that is large in the design that reads as harmless.

Count the sessions, not the verbs

The concrete way to see this is to enumerate what a real profile is signed into. On the laptop in question, Chrome's cookie store held valid session cookies for 34 origins. Nine of them mattered: Okta, which was the single sign-on (SSO) front door, meaning the one place the employee actually types a password and every other service trusts the result, and which had an active session that would silently satisfy redirects from anything federated to it; Google Workspace, which meant mail, Drive and calendar for a person with access to the supplier contracts folder; Salesforce; NetSuite, with a role that could approve purchase orders up to £25,000; GitHub, with write on eleven repositories; the AWS console, reached through Okta, with a role that could read S3 buckets containing customer exports; Confluence; the internal admin panel for the customer support tool, which had no multi-factor authentication (MFA) of its own because it sat behind SSO; and Jira.

That list is worth counting rather than skimming, because it closes exactly. Nine systems were said to carry real authority and nine are named: the identity provider, the productivity suite, the CRM, the finance system, the code host, the cloud console, the wiki, the support admin panel and the issue tracker. Nothing is left over and nothing is asserted without being shown, which means a reader can audit the classification instead of accepting it — and so can the person who disagrees, whose objection is then about whether one particular system belongs, which is an argument with an answer. The remainder is the more useful half of the arithmetic. The origins that did not make the list are not a residue the exercise gave up on; they are the ones where an inherited session buys an attacker nothing, because the origin holds none of your data and grants no action worth taking. A profile is not thirty-four risks with an unknown distribution. It is nine, plus a long tail that is empty for a reason, and those nine are what the rest of the comparison is about.

None of those required a password from the agent. None of them would produce a login event, an MFA prompt, a new-device notification, or an unusual-location alert, because there was no authentication step — the authentication had happened days earlier, performed by the human, and the cookie was still valid.

Why that follows is the load-bearing step of the whole comparison, and it gets skipped because it looks obvious. The protocol underneath these services is stateless: each request arrives carrying no memory of the one before it, so a service that wants to know who is asking has to be told again on every single request. A session cookie is the cheap way of being told again. At some earlier moment the human authenticated — a password, a second factor, a device check — and the service minted a token, handed it to the browser, and agreed to accept that token as proof of that authentication until it expires. From then on the browser attaches the token to every request bound for that origin, without asking anybody, because that is what the browser was built to do. So at the moment the agent drives the browser, no authentication occurs. Not a weak one, not a cached one, not a re-used one: none. A log records events, and an authentication log with no authentication event has nothing to write down. The alerting layered on top of those events — new device, unusual location, a prompt for a second factor — is therefore silent by construction rather than by oversight, and no amount of tuning it will help, because there is no failure here to detect. Every component is doing precisely what it agreed to do, and the absence of an authentication event is the result rather than the oversight.

That is the property that makes an inherited session outrank a code sandbox. The sandbox can execute anything expressible in Python and reaches nothing, so an attacker who fully controls it has a fast computer with no data on it and no way to talk to anyone. The browser agent cannot execute anything, and every action it takes is indistinguishable, in every log those nine systems keep, from the analyst doing it: same session identifier, same source IP, same user agent, same device posture signal. Detection and response both depend on those logs.

Sequence: Hostile page content → Agent (model loop) (rendered text incl. injected instruction); Agent (model loop) → Chrome, analyst profile (navigate + click + type); Chrome, analyst profile → NetSuite (request with existing session cookie); NetSuite → Chrome, analyst profile (200, action performed); Chrome, analyst profile → Agent (model loop) (screenshot of confirmation).

Nothing in that sequence is an attack on the browser. The browser did what browsers do, which is attach the cookies for the origin it is talking to. Every security property the browser enforces — origin isolation, the site-per-process sandbox, cookie SameSite rules, the permission prompts for camera and clipboard — is designed to protect the machine and the user from hostile web content. It is oriented outward from the user. The agent is standing on the user's side of that boundary, holding the user's credentials, and the boundary was never built to constrain anything in that position.

This is why the common argument — the browser is itself a sandbox and the agent can only click things a person could click — has a true premise and an inverted conclusion. "Things the user could click" is not a small set. It is the union of every authority the user holds across every service they are signed into, exercised without any of the friction a human applies to it: no pause before the confirmation dialog, no noticing that the page looks wrong, no memory that this supplier was flagged last month.

Put that defence to the test that separates a control from a slogan, which is to ask whether its answer changes when the thing it is meant to bound changes. "The browser is a sandbox" is exactly as true of a freshly created profile signed into nothing as it is of the profile above with nine authorities in it. The browser's isolation machinery is identical in the two cases, because it is a property of the browser and not of the cookie jar. Meanwhile the quantity the sentence is being asked to bound — how much authority a compromised run spends — runs across its entire range between those two profiles. A defence that is constant while the quantity it must discriminate varies from nothing to everything is not a weak defence. It is a sentence about a different subject. The second half of the argument fails the same test for the same reason: "only things a person could click" describes the agent's verbs, and the verbs were never the variable.

The two designs need different definitions of containment

The word "contain" ends up meaning almost opposite things for the two, which is why a single review checklist applied to both produces nonsense.

A: Python in a hosted sandboxB: Browser control in the user's profile
What it can executeAnything expressible in PythonClicks, keystrokes, navigation
Acts asNothing; an anonymous processThe employee, everywhere they are signed in
Authentication observableN/A — no credentials presentNone; sessions already established
Attribution in target logsNot applicableIdentical to the human's own activity
Attacker's gain on compromiseCompute, plus whatever data was copied inPurchase approval, mail, source code, exports
RevocationKill the sandbox; instant, totalRevoke sessions, rotate SSO, audit nine systems
Containment meansIsolation: no mounts, no creds, no egressReduced authority: separate profile, scoped accounts, domain allowlist, confirmation before state change
Worst plausible outcomeA hostile package exfiltrates the input dataset if egress is ever reopenedA purchase order approved, a repository altered, a Drive folder shared externally

For A, containment is a matter of configuration you can assert on. The failure mode is that the configuration drifts and the sandbox quietly acquires a credential or an egress route, at which point A starts to look like B — worth stating plainly, because a code-execution tool with production credentials mounted is not the smaller problem, it is the same problem arriving through a different door.

For B, isolation is beside the point, because the value of the capability is the identity. A computer-use agent in a hermetic VM with a fresh profile is contained and also useless for the task, since it cannot log into the supplier portal without credentials, and giving it credentials is how the authority comes back. Containment for B is therefore a set of authority decisions rather than a set of isolation decisions: a dedicated browser profile with only the sessions the task requires, service accounts scoped to the specific operations rather than a human's role, a navigation allowlist enforced at the proxy rather than in the prompt, and a human confirmation step on any action that changes state in a system that matters. Each of those costs product quality, which is why they are argued about, and each of them is the actual control.

Simon Willison's framing of the lethal trifecta, which topic 7.3 develops, is a fast way to check whether either design has crossed a line: access to private data, exposure to untrusted content, and a channel to exfiltrate. Any two are survivable; all three in one agent means a hostile instruction in the untrusted content can move the private data out. Proposal A has private data and, with egress denied, no exfiltration channel, so the trifecta is incomplete by construction — and reopening egress completes it, which is exactly why the containment statement pins it. Proposal B has all three the moment it is switched on, because the private data is behind the sessions, the untrusted content is the open web it was built to browse, and navigation itself is the exfiltration channel.

Detection and revocation are the asymmetry made operational

The middle rows of that table describe a security team's working life after something goes wrong, and they are the rows that get skipped in design reviews because they concern the response rather than the design.

Detection for A is straightforward in the sense that anything anomalous is anomalous by construction: the sandbox has no legitimate reason to make an outbound connection, so a single dropped packet at the egress policy is a signal with no false positives. Detection for B has no such property. The organisation's monitoring is built around identity anomalies — impossible travel, a new device, a login at an unusual hour, a burst of downloads from an account that normally downloads nothing. The agent triggers none of the first three, because it is on the analyst's device, on the analyst's network, during the analyst's working day. It can trigger the fourth, and that is the one detection that has a chance, which is worth knowing when you are deciding what to instrument: volume and rate against a per-user baseline is the only signal that survives an inherited session, and it is the noisiest one you own.

Revocation is where the asymmetry becomes a number. Stopping A is docker kill, and there is nothing left; a compromised sandbox holds no state that outlives it. Stopping B means terminating sessions in nine systems, several of which have no administrative session-revocation control at all, then rotating whatever the agent might have read, then working out what it did while it held them. When one organisation ran this as a tabletop exercise, the estimate for a full session revocation and audit across their equivalent nine systems was eleven hours of two people's time, most of it spent establishing which actions in the logs were the human's and which were the agent's — a question with no clean answer, because both had used the same session identifier. That ambiguity is a design output rather than a tooling gap, and it is fixable only by giving the agent a distinct identity, which means not using the human's profile.

Convert that estimate into the unit an engineering manager schedules in and the asymmetry stops being an argument. Eleven hours of two people is twenty-two person-hours, which is most of a working week for one person, spent on a task that produces no product and cannot be started until an incident is already under way. The other side of the comparison is a single command that returns immediately and leaves nothing behind. The gap is not a matter of one design being somewhat harder to clean up. It is the difference between a response with a cost and a response with a duration measured in seconds, and it is decided entirely by whether the agent had an identity of its own.

Where the ranking flips back

None of this makes browser control indefensible or code execution benign, and reading it as "browser bad, sandbox fine" will produce bad calls in both directions within a month.

Code execution becomes the more dangerous of the two whenever it is given reach, and reach accumulates quietly. A sandbox that can install packages from the public registry has an egress path and a supply chain; a sandbox that runs on the same node as other tenants' sandboxes has a shared kernel and a lateral path; a sandbox with a database connection string in its environment holds authority as surely as a cookie does, with the difference that a service account's authority is often broader than any individual human's. Proposal A scored low in this comparison because of its specific containment statement, and a different statement gives a different score.

Attended operation is the other place the ranking is misread. It is often offered as the mitigation for B, on the argument that the analyst is sitting there watching, and it is worth something and much less than it sounds, for reasons that show up in any recording of people supervising an agent: the actions happen faster than a person reads, most of them are correct, and the supervisory attention that survives the first hour is a glance at the summary. Attendance catches the agent doing something visibly strange on screen. It does not catch a single navigation to a URL with data in the query string, which takes 200 ms and looks like the page loading. The arithmetic in that sentence is the whole argument. A person watching a screen is a detector whose sampling interval is set by reading speed, and reading speed is measured in seconds per screenful. The event to be caught completes in a fifth of a second and leaves behind a page that looks like a page. Sampling in seconds against an event that lasts a fraction of one is not a detector with a poor hit rate; it is a detector pointed at a different timescale, and buying more attention does not change the timescale. Treat attendance as a control on obviously wrong behaviour and not as a control on authority.

What separates these two designs is not how much either can do but whose authority it spends. A sandbox with no mounts, no credentials and no egress performs its actions as nobody, so compromising it yields compute; a browser agent in a human's profile performs every action as that human, in systems that record no authentication because none happened, and yields whatever that human is entitled to do.

That ranking is available on paper, before either design exists, which makes it the cheapest security work in this topic and the reason to do it in the review rather than after. It settles a design argument and it does not tell you what a built agent actually reaches on a real machine — a different exercise, with a different failure mode, in which teams tend to measure the wrong quantity and produce a number that improves while the exposure stays exactly where it was.

Computer use, browser use and code execution tools — read the current version at https://daviddominguez.dev/learn/en/computer-use-browser-use-and-code-execution-tools/inherited-browser-sessions

Back to top