deny-read permission profile silently ineffective on native Windows (ACL state empty) — 0.142.5

Open 💬 2 comments Opened Jul 6, 2026 by yoshitakafumoto-xyn

Summary

On native Windows, a permission profile with a valid deny filesystem rule does not
apply read denial. write denial works; read denial does not. Sandboxed commands can
still read files that a deny rule should block (e.g. ~/.codex/config.toml).

Environment

  • codex-cli 0.142.5 (latest stable)
  • Windows 11 Home, build 26200
  • Native Windows sandbox, [windows] sandbox = "elevated" (elevated backend set up)

Config (corrected to documented syntax)

default_permissions = "review-egress"

[permissions.review-egress.filesystem]
"~/.ssh" = "deny"

[permissions.review-egress.filesystem.":workspace_roots"]
"." = "read"

Steps to reproduce

  1. Apply the config above with the elevated Windows sandbox backend.
  2. Run a sandboxed command that reads an absolute path under a deny rule.
  3. Observed: the file is read successfully; deny_read_acl_state.json remains empty ({"principals": {}}).
  4. Expected: read is blocked by policy (parity with write-deny, and with macOS/Linux).

Notes

  • write-deny behaves correctly; only read-deny is ineffective.
  • Non-elevated returns an "elevated backend required" error (i.e. the rule is now

recognized, unlike undocumented keys which were silently ignored).

  • Sandbox log shows "read-acl-only mode: applying read ACLs" completing in ~1ms with no deny ACEs applied.
  • Possibly related: #28566, #30758.

Impact

Any workflow relying on read-deny for secret isolation on native Windows is silently
unprotected, with no error surfaced when the elevated backend is present.

View original on GitHub ↗

2 Comments

kvsentry · 24 days ago

@yoshitakafumoto-xyn Still present on codex-cli 0.147.0-alpha.6 (npm alpha, published 2026-08-03), five minor
versions after the 0.142.5 reported here. Below is some detail from inspecting the file permissions
afterwards, plus one behavior that may point at the underlying cause.

Environment: Windows 11 Pro 10.0.26200, [windows] sandbox = "elevated", elevated backend
installed.

[windows]
sandbox = "elevated"

[permissions.m]
[permissions.m.filesystem]
":root" = "read"
":workspace_roots" = "write"
'C:\Temp\ws3\*.env' = "deny"
'C:\Temp\ws3\exact-secret.txt' = "deny"

The exact path rule and the glob rule fail in different ways

For the exact path rule, Codex does create a deny entry. The problem is what that entry denies:

> icacls C:\Temp\ws3\exact-secret.txt
C:\Temp\ws3\exact-secret.txt S-1-5-21-<redacted>:(DENY)(W,D,Rc,DC)
                             <HOST>\CodexSandboxUsers:(I)(M)
                             ...

> icacls C:\Temp\ws3\secret.env
C:\Temp\ws3\secret.env <HOST>\CodexSandboxUsers:(I)(M)
                       ...

The letters (W,D,Rc,DC) are write, delete, read control, and delete child. There is no read
permission in that list, so reading the file is not affected.

For the glob rule, no deny entry is created at all. The file's permissions are left untouched.

I used *.env rather than **/*.env on purpose. The code warns that ** patterns are not
supported outside macOS and suggests writing explicit patterns such as *.env instead. That
suggested form behaves the same way. **/*.env gave identical results.

The deny rule appears to block writing instead of reading

Same file, same profile:

> codex sandbox -P "m" -C C:\Temp\ws3 -- cmd /c "type exact-secret.txt"
EXACT-SECRET
exit 0

> codex sandbox -P "m" -C C:\Temp\ws3 -- cmd /c "echo TAMPERED>> exact-secret.txt"
Access is denied.
exit 1

> codex sandbox -P "m" -C C:\Temp\ws3 -- cmd /c "echo OK>> public.txt"
exit 0

Reading the file works, which the rule was supposed to prevent. Writing to the file is blocked,
which the rule never asked for. The third command confirms that writing to other files in the same
workspace still works, so the block is specific to the file covered by the deny rule.

This matches the permissions shown above. The deny entry blocks the access that was not requested,
and allows the access that was.

That raises something worth checking. There are several open reports of deny-read entries breaking
writes: #18918 (deny entries on .git breaking commits), #31229 (apply_patch can add files but
cannot update them), and #36087. If a deny-read rule produces a write-deny entry, those reports and
this one may be the same problem seen from opposite sides. I have not confirmed that, and someone
familiar with how these entries are built could rule it in or out quickly.

The log and the state file disagree

granting write ACE to C:\Temp\ws3 for sandbox group and capability SID
applied deny ACE to protect C:\Temp\ws3\exact-secret.txt

Meanwhile .sandbox/deny_read_acl_state.json still contains {"principals": {}}, which matches
what you reported. There is no log line at all for the file matched by the glob, which fits with no
entry being created for it.

@viyatb-oai you added Windows deny-read in #18202 and made deny canonical in #23493, so you may
be the best person to say whether the write-deny entry above is the intended construction or a bug
in how the entry is built. This reproduces reliably here and I am happy to run further tests.

labolabo · 14 days ago

Reproduced on codex-cli 0.145.0 — Windows 11 Pro build 26200, elevated sandbox backend in use.

Symptom matches this issue: custom permission profiles with read-deny rules are parsed and loaded (session records show file_system: restricted, sandboxed commands run as codexsandboxoffline), yet reads outside the workspace still succeed from PowerShell. The deny-read ACL state remains empty ({"principals": {}}) after runs.

Configurations tested (all silently ineffective):

  1. The official workspace-only example from the Permissions docs (":root" = "deny", ":minimal" = "read", workspace write)
  2. Explicit deny entries for three external directories
  3. A glob deny targeting *.md

In all three cases, ordinary files under C:\Users\Public\Documents, the user's Documents folder, and an external drive directory were fully readable from the sandboxed shell (exit code 0, contents returned), while whoami confirmed the restricted identity was active.

Control observations:

  • A test file protected with a manual NTFS deny ACE for the sandbox user was correctly denied (Access is denied, exit code 1). So OS-level enforcement works when ACLs are actually present — the missing piece appears to be the config→ACL projection step.
  • When the profile is requested without the elevated backend set up, the CLI fails closed with Restricted read-only access requires the elevated Windows sandbox backend, which is good. The silent-ineffective behavior above occurs with elevated in use.

One additional note that may help triage: child sessions spawned from a Codex Desktop task inherit CODEX_PERMISSION_PROFILE=:danger-full-access from the parent environment, which overrides the config profile and can mask (or be mistaken for) this bug. The ACL-projection failure reproduces independently after scrubbing that variable from the environment.

Happy to provide fuller transcripts if useful.