fix(sandbox): keep read-only strictly zero-grant by dropping the write-allowlist SID from list I

A session that materialized its workspace-write grant and then switched to read-only (or crashed and resumed under read-only) kept a writable workspace for the server lifetime: the standing orphan-SID ACE survived the downgrade and list I still carried the orphan, so the write-restricted pass-2 check granted it. List I is now [logon SID, EVERYONE] only — the standing ACE stays inert under read-only while the unrevoked ACE keeps the re-upgrade free (map hit, no re-propagation). Pinned by the runner's real-token mode-downgrade regression (standing ACE denied under read-only, effective again on re-upgrade), the acl-session mode-switch cycle (nothing under read-only, one materialization on upgrade, no revoke on downgrade), and ConstrainedLanguage pins in both modes.
This commit is contained in:
Huanqi Cao
2026-08-08 20:11:01 +08:00
parent e9b1c64a38
commit 2dd9af6f4b
10 changed files with 143 additions and 22 deletions

View File

@@ -378,8 +378,12 @@ export class LocalSandboxProvider extends SandboxProvider {
* session's first confined execution, reused for every later call (the map
* hit is the whole call). Workspace-write grants the workspace root and
* the private temp subdirectory (created here); read-only materializes
* NOTHING — its token alone restricts every write. Fail-closed: a
* half-materialized grant is revoked before the error propagates.
* NOTHING — its token alone restricts every write, and a standing grant
* from an earlier workspace-write period is KEPT through a downgrade
* (never revoked): the read-only restricted token carries no orphan SID
* (list I), so the ACE is inert there, while the map hit keeps the
* re-upgrade free of re-propagation. Fail-closed: a half-materialized
* grant is revoked before the error propagates.
* @param record - the session's durable record.
* @param mode - the policy mode (grants exist only under workspace-write).
*/