From 5ff4681c76b78d6b6f16095e03e7e2ad524f6684 Mon Sep 17 00:00:00 2001 From: euxaristia <25621994+euxaristia@users.noreply.github.com> Date: Thu, 9 Jul 2026 07:38:50 -0400 Subject: [PATCH] fix(sandbox): remove windowsWriteRestricted flag to fix DenyRead bypass On Windows, creating restricted tokens with windowsWriteRestricted (0x08) instructs the kernel to skip checking the restricted SIDs list for read operations. This bypasses DenyRead path policies on NTFS. Remove the flag to enforce restricted SID constraints on both read and write operations, and add integration test assertions to verify that DenyRead paths are correctly blocked. --- .../sandbox/runner_windows_integration_test.go | 15 +++++++++++++++ internal/sandbox/windows_token_windows.go | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/sandbox/runner_windows_integration_test.go b/internal/sandbox/runner_windows_integration_test.go index 22a61bfa5..708f43e4c 100644 --- a/internal/sandbox/runner_windows_integration_test.go +++ b/internal/sandbox/runner_windows_integration_test.go @@ -145,12 +145,22 @@ func TestWindowsUnelevatedRealSandboxSmoke(t *testing.T) { root := t.TempDir() outside := t.TempDir() + privateDir := filepath.Join(root, "private") + if err := os.MkdirAll(privateDir, 0o700); err != nil { + t.Fatalf("MkdirAll private: %v", err) + } + secretFile := filepath.Join(privateDir, "secret.txt") + if err := os.WriteFile(secretFile, []byte("super-secret"), 0o600); err != nil { + t.Fatalf("WriteFile secret: %v", err) + } + sandboxHome := filepath.Join(root, ".zero-sandbox") profile := PermissionProfile{ FileSystem: FileSystemPolicy{ Kind: FileSystemRestricted, ReadRoots: []string{root}, WriteRoots: []WritableRoot{{Root: root, ProtectedMetadataNames: []string{".git", ".zero", ".agents"}}}, + DenyRead: []string{privateDir}, IncludePlatformRoots: true, AllowTemp: true, }, @@ -179,6 +189,11 @@ func TestWindowsUnelevatedRealSandboxSmoke(t *testing.T) { t.Fatalf("expected the unelevated setup marker to be recorded: %v", err) } + // DenyRead check: reading from the privateDir must be blocked (exit code 1) + runWindowsRealSmokeCommand(t, runnerExe, config, []string{ + "cmd.exe", "/d", "/s", "/c", "type " + secretFile, + }, 1) + outsideMarker := filepath.Join(outside, "unelevated-write-denied.txt") runWindowsRealSmokeCommand(t, runnerExe, config, []string{ "cmd.exe", "/d", "/s", "/c", "echo leaked>" + outsideMarker, diff --git a/internal/sandbox/windows_token_windows.go b/internal/sandbox/windows_token_windows.go index f95661371..5c5498e74 100644 --- a/internal/sandbox/windows_token_windows.go +++ b/internal/sandbox/windows_token_windows.go @@ -105,7 +105,7 @@ func createWindowsRestrictedTokenFromBase(base windows.Token, capabilitySIDs []w var restricted windows.Token result, _, callErr := procCreateRestrictedToken.Call( uintptr(base), - uintptr(windowsDisableMaxPrivilege|windowsLUAToken|windowsWriteRestricted), + uintptr(windowsDisableMaxPrivilege|windowsLUAToken), 0, 0, 0,