Version / branch / commit
zero 0.6.0 (npm @gitlawb/zero@0.6.0, win32-x64 binary)
- Also present on
main @ 7f39a63
OS and environment
- Windows 11 (virtualized sandbox VM), PowerShell 5.1, elevated (Administrator)
- Native backend:
windows-restricted-token (zero sandbox setup completed successfully from an elevated terminal)
- Go 1.26.5, Node 24.19
Steps to reproduce
-
Install @gitlawb/zero@0.6.0 and run zero sandbox setup from an elevated terminal. It prints Windows sandbox setup complete.
-
Run zero doctor from the same directory — sandbox.backend is [pass] (the setup marker validates for the cwd workspace root).
-
In any small project directory, run:
zero exec --output-format stream-json --max-turns 10 "Run 'go test ./...' and report the result."
-
The agent's exec_command tool call aborts before the command executes.
Expected behavior
exec_command should run inside the native Windows restricted-token sandbox (as zero doctor suggests the backend is ready), just as write_file/read_file/edit_file work.
Actual behavior
Every exec_command aborts immediately with:
zero-windows-command-runner.exe: windows sandbox setup is out of date: permission roots or deny lists changed
The run ends with status: incomplete. File tools work fine — only shell execution is blocked.
Root cause (traced on main @ 7f39a63)
internal/sandbox/runner.go — BuildCommandPlan builds the profile and then calls permissionProfileWithRuntime(profile, runtimeState) (line ~189).
internal/sandbox/runtime_state.go — permissionProfileWithRuntime appends the per-workspace sandbox runtime root (<LocalAppData>/zero/runtime/v1/<sha256(workspaceRoot)[:8]>) as an extra FileSystem.WriteRoots entry when it isn't already present.
internal/sandbox/windows_command_runner_windows.go (restricted-token tier) validates the stored setup marker using the command's profile: ValidateWindowsSandboxSetupMarker(WindowsSandboxSetupConfigFromCommand(config)).
- But
zero sandbox setup (internal/cli/sandbox.go → runSandboxSetup) writes the marker via WriteWindowsSandboxSetupMarker from a profile built without the runtime root.
internal/sandbox/windows_setup.go — ValidateWindowsSandboxSetupMarker compares ACLPlanHash/ACLPlanEntries of the stored marker (no runtime root) against the freshly computed plan from the command profile (with runtime root) → permanent mismatch → permission roots or deny lists changed.
Evidence
- The runtime root appears after the first exec attempt:
C:\Users\<user>\AppData\Local\zero\runtime\v1\55c03089a6535cfb, where 55c03089 = first 8 hex chars of sha256("<workspace>\zero-demo").
- The stored marker's
aclPlanEntries is stable for a given workspace (e.g., 5 for a workspace-only profile), while the command-time plan adds the runtime-root entries → counts/hashes never agree.
zero doctor reports the backend as [pass] because doctor builds its profile the same way as setup (without the runtime root), so the two sides of the validation disagree.
Suggested fix direction
Make the elevated Windows setup include the sandbox runtime root in the profile used both for applying ACLs and for writing the setup marker — i.e. prepare the runtime and apply permissionProfileWithRuntime before BuildWindowsACLPlan / WriteWindowsSandboxSetupMarker in the setup path (runWindowsSandboxSetup / runSandboxSetup), so the command-time profile matches the marker.
Relevant logs
[zero] zero-windows-command-runner.exe: windows sandbox setup is out of date: permission roots or deny lists changed
(zero doctor from the same directory: Overall: pass, sandbox.backend: [pass].)
Version / branch / commit
zero 0.6.0(npm@gitlawb/zero@0.6.0, win32-x64 binary)main@7f39a63OS and environment
windows-restricted-token(zero sandbox setupcompleted successfully from an elevated terminal)Steps to reproduce
Install
@gitlawb/zero@0.6.0and runzero sandbox setupfrom an elevated terminal. It printsWindows sandbox setup complete.Run
zero doctorfrom the same directory —sandbox.backendis[pass](the setup marker validates for the cwd workspace root).In any small project directory, run:
The agent's
exec_commandtool call aborts before the command executes.Expected behavior
exec_commandshould run inside the native Windows restricted-token sandbox (aszero doctorsuggests the backend is ready), just aswrite_file/read_file/edit_filework.Actual behavior
Every
exec_commandaborts immediately with:The run ends with
status: incomplete. File tools work fine — only shell execution is blocked.Root cause (traced on main @ 7f39a63)
internal/sandbox/runner.go—BuildCommandPlanbuilds the profile and then callspermissionProfileWithRuntime(profile, runtimeState)(line ~189).internal/sandbox/runtime_state.go—permissionProfileWithRuntimeappends the per-workspace sandbox runtime root (<LocalAppData>/zero/runtime/v1/<sha256(workspaceRoot)[:8]>) as an extraFileSystem.WriteRootsentry when it isn't already present.internal/sandbox/windows_command_runner_windows.go(restricted-token tier) validates the stored setup marker using the command's profile:ValidateWindowsSandboxSetupMarker(WindowsSandboxSetupConfigFromCommand(config)).zero sandbox setup(internal/cli/sandbox.go→runSandboxSetup) writes the marker viaWriteWindowsSandboxSetupMarkerfrom a profile built without the runtime root.internal/sandbox/windows_setup.go—ValidateWindowsSandboxSetupMarkercomparesACLPlanHash/ACLPlanEntriesof the stored marker (no runtime root) against the freshly computed plan from the command profile (with runtime root) → permanent mismatch →permission roots or deny lists changed.Evidence
C:\Users\<user>\AppData\Local\zero\runtime\v1\55c03089a6535cfb, where55c03089= first 8 hex chars ofsha256("<workspace>\zero-demo").aclPlanEntriesis stable for a given workspace (e.g., 5 for a workspace-only profile), while the command-time plan adds the runtime-root entries → counts/hashes never agree.zero doctorreports the backend as[pass]because doctor builds its profile the same way as setup (without the runtime root), so the two sides of the validation disagree.Suggested fix direction
Make the elevated Windows setup include the sandbox runtime root in the profile used both for applying ACLs and for writing the setup marker — i.e. prepare the runtime and apply
permissionProfileWithRuntimebeforeBuildWindowsACLPlan/WriteWindowsSandboxSetupMarkerin the setup path (runWindowsSandboxSetup/runSandboxSetup), so the command-time profile matches the marker.Relevant logs
(
zero doctorfrom the same directory:Overall: pass,sandbox.backend: [pass].)