OpenAI Codex · 程式碼模式

Windows:受限令牌、防火牆過濾器與兩個專用系統使用者

沒有 seatbelt,也沒有 bubblewrap。Windows 上的沙箱是三道關卡疊起來的:令牌管寫,專用帳戶管你是誰,WFP 按這個身份濾網。AppContainer 對不上這份權限模型,整套還預設關著。

課程目標讀完能說清三件事。Windows 上為什麼只能按身份鎖資源。受限令牌那三個標誌為什麼管得住寫、管不住讀和網路。為什麼要兩個專用系統使用者,以及 AppContainer 為什麼被放下。
先玩一遍 · 一個請求穿過三道關
換動作、換檔位,看請求在哪一關停下
動作
檔位
先看 Elevated 怎麼把讀擋在身份關。再降到 RestrictedToken,同一條讀取會穿過去。
這次請求
讀 C:\Users\you\.ssh\id_rsa
當前身份
CodexSandboxOffline
關卡 1 · 受限令牌待命
三個標誌裁令牌。寫必須過交叉檢查,讀在這一檔仍跟當前使用者走。
關卡 2 · 專用系統使用者待命
Elevated 才登入 CodexSandboxOffline 或 Online,按帳戶 ACL 挖空 .ssh 這類目錄。
關卡 3 · 防火牆過濾器待命
只給離線帳戶裝持久 WFP。ICMP、DNS、SMB 被核心濾掉,普通出站給出站防火牆。
點播放,看這個請求依次走過三道關。
邏輯軌跡 · 動畫每一步對應原始碼裡的哪一段
  1. Windows 開關關著,平臺沙箱返回空,後面不會包包裝器manager.rs L62
  2. 需要沙箱時,用自己的 exe 加隱藏參數當包裝器wrapper.rs L20
  3. 三個標誌裁出受限令牌:削特權、LUA、寫必須過交叉檢查token.rs L480
  4. RestrictedToken 這一檔,讀檢查不看 capability SIDwindows.rs L109
  5. Elevated 先用專用帳戶登入,再從那個令牌往下裁runner_client.rs L348
  6. 兩個帳戶名寫死:Offline 與 Onlinesetup.rs L50
  7. 網路策略未開或走代理時,選 Offline 身份setup.rs L706
  8. 只給離線帳戶裝持久 WFP 過濾器wfp.rs L75
  9. 使用者配置根預設挖空 .ssh 等目錄setup.rs L56
  10. 沒有後端時,只讀檔案加 Never,未匹配命令必須 Forbiddenexec_policy_windows_tests.rs L113
點播放,看這個請求依次走過三道關。
令牌檔只鎖寫RestrictedToken 從當前使用者裁令牌。讀工作區外的檔案、往外發網路,這兩條都會穿過。要攔它們,必須換 Elevated。
身份關才有挖空.ssh 出現在使用者配置排除列表裡。只有登入了專用帳戶,這份 ACL 才會生效。
網路掛在 SID 上WFP 只裝給離線帳戶。令牌檔沒有這兩個帳戶,第三關根本不存在。
教學示意:路徑與帳戶名為課程化設定。邏輯軌跡右側行號對應 openai/codex 倉庫 commit 4f39251a01。
思路一 · 沒有行程視圖,就按身份鎖資源
它解決什麼問題

同事在 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_PRIVILEGELUA_TOKENWRITE_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 行

macOS 鎖行程能做什麼 SBPL 文字 file-read 規則拒絕 Operation not permitted Linux 鎖行程能看見什麼 bubblewrap 視圖 路徑不在掛載裡 No such file or directory Windows 鎖這個身份能碰什麼 令牌加 ACL 身份沒有權限 Access is denied
教學化結構圖:同一條讀取,三套隔離鎖在不同層,模型看到的失敗語義也不一樣。
為什麼長期成立

主體能做什麼,和客體能被誰碰,是兩套隔離原語。換語言重寫,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 只能對應一套網路策略。同一身份沒法同時表示完全沒網,也沒法同時表示可以走代理或出網。

思路是什麼

所以用兩個本地使用者當兩個網路身份:CodexSandboxOfflineCodexSandboxOnlinefrom_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 行

一個 SID,兩套互相打架的網策 同一個帳戶 完全沒網 可以走代理或出網 過濾器按 SID 匹配,裝不上兩套 兩個帳戶,兩套網策 CodexSandboxOffline 12 條 WFP 加出站阻斷 Online 不裝這套阻斷 出網
教學化結構圖:網路策略有兩檔,就需要兩個身份。
為什麼長期成立

按身份做訪問控制,身份數量必須覆蓋策略組合數。網路策略有兩檔,就需要兩個身份。這和用兩張門禁卡進兩棟樓是同一件事,跟 WFP 這個具體 API 無關。

思路三 · AppContainer 對不上,Elevated 又太貴,所以預設關
它解決什麼問題

有人會問為什麼不上 AppContainer。它的可讀範圍預設很窄,任意路徑讀取要改宿主 DACL。Codex 需要 workspace 可讀、平臺根可讀,再按 deny 列表挖空。受限令牌加 ACL 更貼這份權限模型。在 codex-rs/ 裡檢索 AppContainer,業務程式碼零命中。對照倉庫 DeepSeek Harness 把同一判斷寫成了明文:AppContainer 做不了任意路徑讀取。

Elevated 要把讀和網路也管住,就要建帳戶、彈 UAC、改防火牆和 WFP。企業策略可能禁止本地建使用者。把預設設成 Disabled,等於把這道產品摩擦留給第一次啟用。

思路是什麼

列舉自己把預設值寫成關。沒寫 windows.sandbox、兩個 legacy flag 也沒有時,就落回 Disabled。legacy flag 已經被標成 Removed。

codex-rs/protocol/src/config_types.rs第 297 至 302 行
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 行

AppContainer 預設可讀範圍很窄 任意路徑要改宿主 DACL 對不上這份權限模型 組合拳 令牌鎖寫 專用帳戶鎖讀 WFP 按 SID 濾網 要 UAC,要本地使用者 預設 Disabled execpolicy 兜底
教學化結構圖:用得上的那套太貴,預設先關,策略層兜住裸跑。
三道關卡,一道管寫,一道管你是誰,一道管這個身份能出哪扇網門。
為什麼長期成立

隔離深度跟安裝預算掛鉤。只防模型誤改倉庫,當前使用者受限令牌就夠。要防讀出金鑰再從這臺機器往外傳,必須再做讀限制和按身份的網路過濾。承諾了做不到的牆,模型和使用者都會按那道牆做決策。

跨平臺能力不對等時,對外說法必須按實際啟用的那一層來寫。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/landlockmacos/seatbelt,其餘標 unknown。在 xai-grok-sandbox 裡檢索 AppContainerRestrictedTokenCreateRestrictedToken,沒有對應實現。

答案分成三檔。Claude 和 Grok 在 Windows 上不做檔案系統沙箱。DSH 做了寫限制,裝得上,讀和網路留給別的機制。Codex 把身份、ACL、WFP、專用帳戶全做進去,摩擦更大,所以預設關著。

已核對 Claude PowerShellTool.tsx、Grok types.rs · 2026-08-22 · Grok · 五種沙箱 Profile
課堂練習
01

同一條讀取,換檔之後卡在哪

把演示裡的動作留在讀工作區外,檔位從 Elevated 降到 RestrictedToken。先寫下你的預測:哪一關會放行,哪一關會消失,最後是 Access is denied 還是穿過。再點播放核對。

進階一問:把動作換成發網路。為什麼 RestrictedToken 檔第三關是跳過,Elevated 檔才會亮起 WFP。

Takeaway:Windows 沒有 seatbelt 和 bubblewrap,隔離只能按身份鎖資源。RestrictedToken 那三個標誌管寫,不管讀和網路。要攔金鑰和出網,必須再上專用帳戶、ACL 和按 SID 裝的 WFP。AppContainer 對不上這份可讀集合,Elevated 又要 UAC,所以預設關著,execpolicy 在沒有後端時改成 Forbidden 或 Prompt。