Repository navigation
fix(security): judge a run's tab between turns; an allow arrival consents navigation only (#1129) - #1131
Conversation
…ents navigation only (#1129) A commit while no turn ran found no judge, was marked judged anyway, and the next turn re-adopted the run on a page a policy denies or asks about (reading its page info into the model). The tab is now watched between turns (watchBetweenTurns), holdStands and judgeTurnStart judge any page the run's judge has not spoken on, and lastJudged is written only when a judge ran. An allow row's arrival now consents its origin for navigation only (navOnlyOrigins), matching the FETCH_URL choke point: an uncredentialed read there goes to its card instead of being refused silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Reviewed. No finding. Rule 10 holds. The diff touches six files: Every committed navigation of the run's tab is judged over its lifetime, fail closed. Three paths cover every window:
The
85/85 nav tests pass (81 existing + 4 new). The four new tests cover: hand-move between turns to an ask page, denied page between turns holding the next turn, follow-up on the same page not re-asked, and allow-arrival consenting navigation only.
|
Fixes the two findings of the navigate red-team pass in #1129 (finder: window-ml-redteam-e3).
1. A commit between turns was never judged (open escape)
settle()removed the run's arrival judge at turn end,judgeArrivalstill wrotelastJudgedwith no judge registered, andholdStandsre-judged only a run already held. A hand-move, redirect or timer between turns to a page a policy denies or asks about was never judged: the follow-up'sadoptOnTab(and CONTENT_READY) re-adopted the run there, which also read that page's info into the model, and the next turn acted freely.watchBetweenTurns(nav-arrival.ts): fromsettle()until the session is released, a commit holds or clears the run with no card. Both re-adopt paths already skip a held run.holdStandsjudges the page when the run is held or when no judge of this run has spoken on that URL, and holds the run on a deny or ask. After an eviction nothing is remembered, so it judges (fail closed).judgeTurnStart(replaces the turn-startjudgeArrival) judges that page for this run, queued so no tool of the turn reaches the page first (arrivalSettled). A run's first turn takes the person's start page as judged.lastJudgedis written only when a judge ran.forgetArrivalRun(fromreleaseSessionTokens) drops the run's hold, its between-turns judge and its last judged URL; a closed tab drops its judges.2. An allow row's arrival consented reads the choke point refuses (layering split)
Per the 2026-10-25 ruling (narrow): an allow row's arrival now puts its origin in a turn-local
navOnlyOrigins, read by the navigate gate only, notconsentedOrigins. An uncredentialedfetch_urlthere goes to its card instead of being refused silently at the FETCH_URL choke point. The card carries no line saying why yet: that is a new public string and waits for approval.Tests
Four new tests in
tests/nav-arrival-host.test.mjs, section "a page the tab moved to BETWEEN turns" plus one under ruling (b): an asked page reached between turns is asked about once at the next turn's start; a denied page reached between turns holds the next turn and is not re-adopted; a follow-up on an approved page and a first turn on the start page ask nothing; an allow arrival's plain GET cards. The two between-turn tests failed against main's bundle. Fullnpm test: 6959 pass, 0 fail.For #1129 after this merges (not edited here)
tests/nav-navigate-redteam.test.mjs: the ruling (b) test at ~277 needscardsto be["click","click","fetch_url","fetch_url"], and itsCHOKE_REFUSEDassert at ~279 drops (the plain GET is refused on its card). The BETWEEN-TURN GAPtest.todopasses as a plain test on this build. e3 updates its own file.Still open
The start origin shows the same gate / choke-point split: consented at the gate, refused at the choke point once the tab has left it (e3's start-origin pin). Not changed here; owned by the security lane.
Docs: docs/dev/agent-tools.md (Arrivals), docs/dev/site-access.md (origin-wide auto-approvals).
🤖 Generated with Claude Code