Windows:受限令牌、防火牆過濾器與兩個專用系統用戶
沒有 seatbelt,也沒有 bubblewrap。Windows 上的沙箱是三道關卡疊起來的:令牌管寫,專用帳戶管你是誰,WFP 按這個身份濾網。AppContainer 對不上這份權限模型,整套還預設關着。
- Windows 開關關着,平台沙箱返回空,後面不會包包裝器manager.rs L62
- 需要沙箱時,用自己的 exe 加隱藏參數當包裝器wrapper.rs L20
- 三個標誌裁出受限令牌:削特權、LUA、寫必須過交叉檢查token.rs L480
- RestrictedToken 這一檔,讀檢查不看 capability SIDwindows.rs L109
- Elevated 先用專用帳戶登入,再從那個令牌往下裁runner_client.rs L348
- 兩個帳戶名寫死:Offline 與 Onlinesetup.rs L50
- 網絡策略未開或走代理時,選 Offline 身份setup.rs L706
- 只給離綫帳戶裝持久 WFP 過濾器wfp.rs L75
- 用戶配置根預設挖空 .ssh 等目錄setup.rs L56
- 沒有後端時,只讀檔案加 Never,未匹配命令必須 Forbiddenexec_policy_windows_tests.rs L113
同事在 Mac 上跑 Codex,agent 去碰用戶目錄裏的 SSH 私鑰路徑,立刻被 Seatbelt 攔住,錯誤寫着 Operation not permitted。同一條讀取放到 Windows 上,報錯變成 Access is denied。再換一台沒開 Windows 沙箱的機器,這條命令可能根本走不到 ACL,execpolicy 先把它判成 Forbidden 或 Prompt。
三台機器、同一份意圖、三種失敗。模型看到的下一句話不一樣,下一步也會跟着變。如果 Windows 上假裝有和 Unix 一樣的預設沙箱,模型會按自己被關着去規劃,實際命令裸跑。
macOS 限制這個進程能對哪些路徑做哪些操作。Linux 限制這個進程能看見什麼、能調哪些系統調用。Windows 沒有 namespace,也沒有 seccomp。Codex 換成另一套問題:這個身份能碰哪些資源。
令牌決定你是誰。RestrictedToken 檔從當前用戶令牌裁,Elevated 檔先用專用帳戶登入,再從那個令牌裁。兩邊最後都進同一組標誌:DISABLE_MAX_PRIVILEGE、LUA_TOKEN、WRITE_RESTRICTED。特權被削薄,寫必須同時通過普通 ACL 和 restricting SID 的交叉檢查。
讀在 RestrictedToken 這一檔仍然跟當前用戶走。源碼自己寫了:WRITE_RESTRICTED 令牌上的 capability SID deny-read ACE 不參與讀檢查,所以讀限制必須走 Elevated,裸跑會被直接拒絕。出處:codex-rs/windows-sandbox-rs/src/token.rs 第 480 行;codex-rs/sandboxing/src/windows.rs 第 109 至 117 行
主體能做什麼,和客體能被誰碰,是兩套隔離原語。換語言重寫,Windows 上仍然沒有 bwrap 可以調用。該問的還是:你有沒有一份身份,這份身份被允許碰什麼。
包裝方式也是同一類自我調用。Windows 用自己的 exe 加上隱藏參數 --run-as-windows-sandbox,跟 Linux 改 arg0 是同一思路。出處:codex-rs/windows-sandbox-rs/src/wrapper.rs 第 20 行
WFP 是 Windows Filtering Platform,一套內核裏的包過濾框架。它和防火牆規則都按 SID 匹配。一個 SID 只能對應一套網絡策略。同一身份沒法同時表示完全沒網,也沒法同時表示可以走代理或出網。
所以用兩個本地用戶當兩個網絡身份:CodexSandboxOffline 和 CodexSandboxOnline。from_permissions 在強制走代理,或網絡策略未啓用時,選 Offline。離綫身份裝出站阻斷、代理端口白名單,再加 12 條 WFP,覆蓋 ICMP、DNS 53、DNS-over-TLS 853 和 SMB。在綫身份不裝這套阻斷。
Unix 的網絡隔離是給進程換一張網卡視圖。WFP 是進程還在主機網絡棧上,只是這個 SID 發出的特定流量被擋住。進程仍然能看見網卡、解析失敗、連別的端口。
過濾器用穩定 GUID 標識,帶着持久標誌,重啓後還在。卸載和崩潰都不會自動拆掉它們。倉庫裏檢索不到刪除用戶或拆除 WFP 的函式。WFP 失敗被寫成非致命,防火牆失敗會讓 setup 整段失敗。出處:codex-rs/windows-sandbox-rs/src/setup.rs 第 50 至 51 行、第 706 至 714 行;codex-rs/windows-sandbox-rs/src/wfp.rs 第 69 至 95 行
按身份做存取控制,身份數量必須覆蓋策略組合數。網絡策略有兩檔,就需要兩個身份。這和用兩張門禁卡進兩棟樓是同一件事,跟 WFP 這個具體 API 無關。
有人會問為什麼不上 AppContainer。它的可讀範圍預設很窄,任意路徑讀取要改宿主 DACL。Codex 需要 workspace 可讀、平台根可讀,再按 deny 列表挖空。受限令牌加 ACL 更貼這份權限模型。在 codex-rs/ 裏檢索 AppContainer,業務程式碼零命中。對照倉庫 DeepSeek Harness 把同一判斷寫成了明文:AppContainer 做不了任意路徑讀取。
Elevated 要把讀和網絡也管住,就要建帳戶、彈 UAC、改防火牆和 WFP。企業策略可能禁止本地建用戶。把預設設成 Disabled,等於把這道產品摩擦留給第一次啓用。
枚舉自己把預設值寫成關。沒寫 windows.sandbox、兩個 legacy flag 也沒有時,就落回 Disabled。legacy flag 已經被標成 Removed。
pub enum WindowsSandboxLevel {
#[default]
Disabled,
RestrictedToken,
Elevated,
}
openai/codex,核對檔案 codex-rs/protocol/src/config_types.rs,commit 4f39251a01,核對日期 2026-08-22。程式碼塊保留源碼原文,#[default] 釘在 Disabled 上。關掉之後,平台沙箱確實沒了。get_platform_sandbox(false) 在 Windows 上返回空,select_initial 把它變成 SandboxType::None。命令仍可能被策略層攔住。Windows 測試鎖住了這條:沒有後端時,只讀檔案加 Never 審批,未匹配的 cmd.exe /c dir 必須是 Decision::Forbidden。出處:codex-rs/sandboxing/src/manager.rs 第 62 至 72 行、第 301 行;codex-rs/core/src/exec_policy_windows_tests.rs 第 113 至 130 行
隔離深度跟安裝預算掛鈎。只防模型誤改倉庫,當前用戶受限令牌就夠。要防讀出密鑰再從這台機器往外傳,必須再做讀限制和按身份的網絡過濾。承諾了做不到的牆,模型和用戶都會按那道牆做決策。
跨平台能力不對等時,對外説法必須按實際啓用的那一層來寫。macOS 預設就有 Seatbelt,Windows 預設可能是 Disabled。用戶聽到有沙箱,會以為三台機器同一道牆。
DeepSeek Harness:同一組標誌,停在寫限制
DSH 的 @deepseek-ai/dsh-sandbox-windows-acl 用同一組 CreateRestrictedToken 標誌:DISABLE_MAX_PRIVILEGE | LUA_TOKEN | WRITE_RESTRICTED。README 寫明讀、網絡、進程可見性不受限,enforcement 標成 partial。它不建專用帳戶,不裝 WFP。
設計筆記把 AppContainer 否掉的原因寫死了:AppContainer 令牌沒有環境讀權限,任意路徑讀取必須預先授權,對不上 harness 的讀模型。mxc 被否是因為系統版本底綫太新,任意路徑讀取還是要改宿主 DACL。Codex Elevated 用兩個帳戶加 WFP 把讀和網絡身份也做進去,代價是安裝摩擦和卸載殘留。DSH 換到的是裝得上、跑得動,讀側和網絡側留給別的機制。
已核對 DSH token.ts / win32-abi.ts / README / 設計筆記 · 2026-08-22 · DSH · 沙箱:從 seatbelt 到執行世界Claude 拒絕執行,Grok 把平台標成 unknown
Claude Code 在原生 Windows 上寫明沒有沙箱。企業策略要求沙箱且禁止無沙箱命令時,PowerShell 直接拒絕執行,文案是 sandboxing is not available on native Windows。它不假裝有一層隔離。Grok Build 的沙箱 crate 把平台寫成 linux/landlock 和 macos/seatbelt,其餘標 unknown。在 xai-grok-sandbox 裏檢索 AppContainer、RestrictedToken、CreateRestrictedToken,沒有對應實現。
答案分成三檔。Claude 和 Grok 在 Windows 上不做檔案系統沙箱。DSH 做了寫限制,裝得上,讀和網絡留給別的機制。Codex 把身份、ACL、WFP、專用帳戶全做進去,摩擦更大,所以預設關着。
已核對 Claude PowerShellTool.tsx、Grok types.rs · 2026-08-22 · Grok · 五種沙箱 Profile同一條讀取,換檔之後卡在哪
把演示裏的動作留在讀工作區外,檔位從 Elevated 降到 RestrictedToken。先寫下你的預測:哪一關會放行,哪一關會消失,最後是 Access is denied 還是穿過。再點播放核對。
進階一問:把動作換成發網絡。為什麼 RestrictedToken 檔第三關是跳過,Elevated 檔才會亮起 WFP。