OpenAI Codex · Code Mode

Windows: restricted token, firewall filter, and two dedicated system users

No seatbelt, and no bubblewrap. The Windows sandbox is three gates stacked: the token governs writes, a dedicated account governs who you are, and WFP filters the network by that identity. AppContainer does not fit this permission model, and the whole stack is off by default.

Course goalAfter this lesson you can explain three things. Why Windows can only lock resources by identity. Why those three restricted-token flags can hold writes but not reads or the network. Why two dedicated system users exist, and why AppContainer was set aside.
Try it first · One request through three gates
Swap actions and tiers, see which gate stops the request
Action
Tier
Watch Elevated block a read at the identity gate. Drop to RestrictedToken and the same read walks through.
This request
Read C:\Users\you\.ssh\id_rsa
Current identity
CodexSandboxOffline
Gate 1 · Restricted tokenStandby
Three flags cut the token. Writes must pass a cross-check; reads at this tier still follow the current user.
Gate 2 · Dedicated system userStandby
Only Elevated logs in as CodexSandboxOffline or Online, and hollows out directories like .ssh via the account ACL.
Gate 3 · Firewall filterStandby
Persistent WFP is installed only for the offline account. ICMP, DNS, and SMB are filtered in the kernel; ordinary outbound goes to the outbound firewall.
Hit Play to watch this request walk the three gates.
Logic trail · each animation step maps to a source span
  1. Windows switch is off; the platform sandbox returns empty; no wrapper is wrapped latermanager.rs L62
  2. When a sandbox is needed, use its own exe plus a hidden flag as the wrapperwrapper.rs L20
  3. Three flags cut a restricted token: strip privileges, LUA, writes must pass a cross-checktoken.rs L480
  4. At the RestrictedToken tier, the read check does not look at capability SIDswindows.rs L109
  5. Elevated logs in with a dedicated account first, then cuts down from that tokenrunner_client.rs L348
  6. Two account names are hard-coded: Offline and Onlinesetup.rs L50
  7. When network policy is off or a proxy is used, pick the Offline identitysetup.rs L706
  8. Install persistent WFP filters only for the offline accountwfp.rs L75
  9. The user-profile root hollows out .ssh and similar directories by defaultsetup.rs L56
  10. With no backend, a read-only profile plus Never means unmatched commands must be Forbiddenexec_policy_windows_tests.rs L113
Hit Play to watch this request walk the three gates.
The token tier only locks writesRestrictedToken cuts a token from the current user. Reading a file outside the workspace, and sending traffic out, both walk through. To stop them you must switch to Elevated.
Only the identity gate hollows things out.ssh sits on the user-profile exclusion list. That ACL takes effect only after a dedicated account is logged in.
The network hangs on a SIDWFP is installed only for the offline account. The token tier has neither account, so the third gate does not exist.
Teaching sketch: paths and account names are course fixtures. Line numbers on the logic trail match openai/codex commit 4f39251a01.
Idea 1 · No process view, so lock resources by identity
What problem it solves

A teammate runs Codex on a Mac; the agent touches an SSH private-key path in the user profile; Seatbelt stops it at once, and the error says Operation not permitted. Put the same read on Windows and the error becomes Access is denied. Switch to a machine that never turned on the Windows sandbox, and the command may never reach an ACL — execpolicy already marks it Forbidden or Prompt.

Three machines, one intent, three failures. The next sentence the model sees is different, so the next step changes with it. If Windows pretends it has the same default sandbox as Unix, the model plans as if it is confined — while the command runs naked.

What the idea is

macOS limits which operations this process may do on which paths. Linux limits what this process can see and which syscalls it can make. Windows has no namespace and no seccomp. Codex asks a different question: which resources can this identity touch.

The token decides who you are. The RestrictedToken tier cuts from the current-user token; the Elevated tier logs in with a dedicated account first, then cuts from that token. Both ends land on the same flags: DISABLE_MAX_PRIVILEGE, LUA_TOKEN, WRITE_RESTRICTED. Privileges are thinned; a write must pass both the ordinary ACL and a restricting-SID cross-check.

At the RestrictedToken tier, reads still follow the current user. The source says so itself: a capability-SID deny-read ACE on a WRITE_RESTRICTED token does not join the read check, so read limits must go through Elevated; a naked run is refused outright.Source: codex-rs/windows-sandbox-rs/src/token.rs line 480;codex-rs/sandboxing/src/windows.rs lines 109–117

macOS Lock what the process can do SBPL text file-read rule denies Operation not permitted Linux Lock what the process can see bubblewrap view Path is not in the mounts No such file or directory Windows Lock what this identity can touch Token plus ACL Identity has no permission Access is denied
Teaching diagram: the same read, three isolation stacks lock different layers, and the failure semantics the model sees are not the same.
Why it lasts

What a subject can do, and who may touch an object, are two isolation primitives. Rewrite it in another language: Windows still has no bwrap to call. The question remains: do you have an identity, and what is that identity allowed to touch.

The wrap is the same family of self-invocation. Windows uses its own exe plus a hidden --run-as-windows-sandbox flag — the same idea as Linux rewriting arg0.Source: codex-rs/windows-sandbox-rs/src/wrapper.rs line 20

Idea 2 · One identity can carry only one network policy
What problem it solves

WFP is the Windows Filtering Platform, a kernel packet-filter framework. It and the firewall rules both match on SID. One SID can carry only one network policy. The same identity cannot mean “no network at all” and also “may use a proxy or go outbound.”

What the idea is

So two local users become two network identities: CodexSandboxOffline and CodexSandboxOnline. from_permissions picks Offline when a proxy is forced, or when network policy is off. The offline identity installs outbound blocks, a proxy-port allowlist, then 12 WFP rules covering ICMP, DNS 53, DNS-over-TLS 853, and SMB. The online identity does not install that block set.

Unix network isolation swaps the NIC view the process sees. WFP leaves the process on the host network stack; only certain traffic from this SID is blocked. The process can still see NICs, fail DNS, and connect to other ports.

Filters are identified by stable GUIDs, carry a persist flag, and survive reboot. Uninstall and crash do not tear them down automatically. The repo has no function that deletes the users or removes WFP. A WFP failure is written as non-fatal; a firewall failure fails the whole setup.Source: codex-rs/windows-sandbox-rs/src/setup.rs lines 50–51、lines 706–714;codex-rs/windows-sandbox-rs/src/wfp.rs lines 69–95

One SID, two network policies that fight The same account No network at all May use a proxy or go outbound Filters match by SID; two sets will not install Two accounts, two network policies CodexSandboxOffline 12 WFP rules plus outbound blocks Online Does not install that block set Outbound
Teaching diagram: two network-policy tiers need two identities.
Why it lasts

When access control is by identity, the number of identities must cover the number of policy combinations. Two network-policy tiers need two identities. It is the same as two badge cards for two buildings — independent of WFP as a concrete API.

Idea 3 · AppContainer does not fit, Elevated is too expensive, so default off
What problem it solves

Someone will ask why not AppContainer. Its default readable range is narrow; arbitrary-path reads require changing the host DACL. Codex needs the workspace readable, the platform root readable, then hollow-outs from a deny list. A restricted token plus ACL fits this permission model better. Search AppContainer under codex-rs/ and business code has zero hits. The comparison repo DeepSeek Harness writes the same judgment in plain text: AppContainer cannot do arbitrary-path reads.

For Elevated to also govern reads and the network, you must create accounts, pop UAC, and change the firewall and WFP. Enterprise policy may forbid creating local users. Setting the default to Disabled leaves that product friction for the first enable.

What the idea is

The enum itself writes the default as off. If windows.sandbox is unset and both legacy flags are absent, it falls back to Disabled. The legacy flags are already marked Removed.

codex-rs/protocol/src/config_types.rslines 297–302
pub enum WindowsSandboxLevel {
    #[default]
    Disabled,
    RestrictedToken,
    Elevated,
}
Source snapshot note: based on the local openai/codex repo; verified file codex-rs/protocol/src/config_types.rs, commit 4f39251a01, verified 2026-08-22. The code block keeps the original source; #[default] is pinned on Disabled.

After it is off, the platform sandbox is truly gone. get_platform_sandbox(false) returns empty on Windows; select_initial turns that into SandboxType::None. The command may still be stopped at the policy layer. A Windows test locks this in: with no backend, a read-only profile plus Never approval means unmatched cmd.exe /c dir must be Decision::Forbidden.Source: codex-rs/sandboxing/src/manager.rs lines 62–72、line 301;codex-rs/core/src/exec_policy_windows_tests.rs lines 113–130

AppContainer Default readable range is narrow Arbitrary paths need a host DACL change Does not fit this permission model The combo Token locks writes Dedicated account locks reads WFP filters the net by SID Needs UAC, needs a local user Default Disabled execpolicy as the backstop
Teaching diagram: the set that actually works is expensive, so default off first; the policy layer catches a naked run.
Three gates: one governs writes, one governs who you are, one governs which network door this identity may leave through.
Why it lasts

Isolation depth is tied to the install budget. If you only want to stop the model from accidentally editing the repo, a current-user restricted token is enough. To stop secrets being read and sent off this machine, you also need read limits and identity-based network filtering. Promise a wall you cannot build, and both the model and the user will decide against that wall.

When platforms are unequal, the public story must be written against the layer that is actually on. macOS has Seatbelt by default; Windows may default to Disabled. Users who hear “there is a sandbox” will think three machines share one wall.

Side-by-side · the same flags, three prices people will pay

DeepSeek Harness: the same flags, stop at write limits

DSH’s @deepseek-ai/dsh-sandbox-windows-acl uses the same CreateRestrictedToken flags: DISABLE_MAX_PRIVILEGE | LUA_TOKEN | WRITE_RESTRICTED. The README says reads, network, and process visibility are unrestricted; enforcement is marked partial. It does not create dedicated accounts and does not install WFP.

The design note writes the AppContainer rejection in stone: an AppContainer token has no ambient read, arbitrary-path reads must be pre-authorized, and that does not fit the harness read model. mxc was rejected because the OS-version floor is too new, and arbitrary-path reads still need a host DACL change. Codex Elevated puts reads and a network identity in with two accounts plus WFP; the cost is install friction and leftover state after uninstall. DSH traded for something that installs and runs, leaving reads and the network to other mechanisms.

Checked DSH token.ts / win32-abi.ts / README / design notes · 2026-08-22 · DSH · Sandbox: from seatbelt to the execution world

Claude refuses to run; Grok marks the platform unknown

Claude Code writes plainly that there is no sandbox on native Windows. When enterprise policy requires a sandbox and forbids unsandboxed commands, PowerShell refuses to run, with the copy sandboxing is not available on native Windows. It does not pretend there is a layer of isolation. Grok Build’s sandbox crate writes platforms as linux/landlock and macos/seatbelt, and marks the rest unknown. Search xai-grok-sandbox for AppContainer, RestrictedToken, CreateRestrictedToken — no matching implementation.

The answer splits into three tiers. Claude and Grok do no filesystem sandbox on Windows. DSH does write limits, installs cleanly, and leaves reads and the network to other mechanisms. Codex puts identity, ACL, WFP, and dedicated accounts all in — more friction, so it stays off by default.

Checked Claude PowerShellTool.tsx and Grok types.rs · 2026-08-22 · Grok · Five sandbox Profiles
Classroom Exercise
01

The same read — after you change tiers, where does it stick

Leave the demo action on reading outside the workspace, then drop the tier from Elevated to RestrictedToken. Write your prediction first: which gate allows, which gate vanishes, and whether the end is Access is denied or a walk-through. Then hit Play to check.

Advanced: switch the action to sending network. Why is the third gate skipped at RestrictedToken, and why does WFP light up only at Elevated?

Takeaway: Windows has no seatbelt and no bubblewrap; isolation can only lock resources by identity. Those three RestrictedToken flags govern writes, not reads or the network. To stop secrets and outbound traffic you also need dedicated accounts, ACLs, and WFP installed by SID. AppContainer does not fit this readable set, and Elevated wants UAC, so the default stays off; with no backend, execpolicy becomes Forbidden or Prompt.