HARDENING-ROADMAP P0-2 is mostly shipped — the relay routes now require isOffscreenSender (an exact match on the offscreen document URL, not merely "first-party") and a SW-minted per-run grant carrying run identity and liveness. Two things remain, one of them a live pre-existing hole.
1. actor/abort accepts a runId from any first-party sender
extension/offscreen/offscreen.js — any extension page, engine tab pages included, can cancel an in-flight actor turn just by naming its runId. Engine tabs host sandboxed content; a page that reaches this route can deny service to the agent's own work.
This is smaller and more concrete than the rest of the issue and can land on its own. It should get the same sender pin the relay routes already have.
2. Targeted delivery via per-run MessagePorts
Today the actor/run job — grant token included — is broadcast to every listener in the extension, because runtime.sendMessage has no way to address a single context. The design compensates honestly: the sender pin is the real boundary precisely because the token is not a secret from those pages.
A MessagePort bound at spawn to (actor, session, generation) would:
- stop broadcasting the job at all,
- make the grant genuinely private rather than a shared value defended by a separate check,
- let the relays drop payload identity entirely.
That collapses two overlapping checks into one structural property, which is the better end state. It is not a 1.0 blocker in my read — the current pairing is sound, just belt-and-braces where it could be architecture — but it is the natural next step and it also gives item 1 above a principled fix rather than another sender check.
Related: extension/background/offscreen-actor-client.js, extension/shared/sender-trust.js, extension/offscreen/offscreen.js.
HARDENING-ROADMAP P0-2 is mostly shipped — the relay routes now require
isOffscreenSender(an exact match on the offscreen document URL, not merely "first-party") and a SW-minted per-run grant carrying run identity and liveness. Two things remain, one of them a live pre-existing hole.1.
actor/abortaccepts a runId from any first-party senderextension/offscreen/offscreen.js— any extension page, engine tab pages included, can cancel an in-flight actor turn just by naming itsrunId. Engine tabs host sandboxed content; a page that reaches this route can deny service to the agent's own work.This is smaller and more concrete than the rest of the issue and can land on its own. It should get the same sender pin the relay routes already have.
2. Targeted delivery via per-run MessagePorts
Today the
actor/runjob — grant token included — is broadcast to every listener in the extension, becauseruntime.sendMessagehas no way to address a single context. The design compensates honestly: the sender pin is the real boundary precisely because the token is not a secret from those pages.A
MessagePortbound at spawn to (actor, session, generation) would:That collapses two overlapping checks into one structural property, which is the better end state. It is not a 1.0 blocker in my read — the current pairing is sound, just belt-and-braces where it could be architecture — but it is the natural next step and it also gives item 1 above a principled fix rather than another sender check.
Related:
extension/background/offscreen-actor-client.js,extension/shared/sender-trust.js,extension/offscreen/offscreen.js.