openai / openai/codex

`CODEX_HOME` fails to load inside a Windows AppContainer/lowbox — `find_codex_home()`'s `canonicalize()` needs `\GLOBAL??` DOS-drive-letter access the sandbox denies

Open Beginner friendly
#45,871 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI config sandbox windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Summary

When CODEX_HOME is set and codex runs inside a Windows AppContainer (lowbox token), startup fails with:

WARNING: proceeding, even though we could not create PATH aliases: failed to canonicalize CODEX_HOME "<dir>": Access is denied. (os error 5)
Error loading configuration: failed to canonicalize CODEX_HOME "<dir>": Access is denied. (os error 5)

even though the process can otherwise read and write that same directory. The cause is find_codex_home() calling
PathBuf::from(val).canonicalize() on CODEX_HOME. std::fs::canonicalize on Windows resolves the final path via
GetFinalPathNameByHandleW(..., VOLUME_NAME_DOS), and an AppContainer token cannot resolve the C:\ DOS drive
letter
because that requires access to \GLOBAL??\C: (the DosDevices symbolic link in the object namespace), which
lowbox tokens are denied. It is not a filesystem-ACL problem — granting the package/capability SID or ALL APPLICATION PACKAGES on the directory (or the drive root) does not help.

This matters because per-agent isolation on Windows (e.g. running multiple codex instances each confined to its own
CODEX_HOME inside its own AppContainer — the same AppContainer approach OpenAI's own Codex Windows sandbox uses) is
exactly the case that must set CODEX_HOME, and it's the only find_codex_home() branch that canonicalizes.

Root cause (isolated empirically)

Inside an AppContainer, we decomposed what canonicalize does with a native probe on the process's own
(read/writable) directory:

Step API Result inside AppContainer
Open the dir CreateFileW(access=0, FILE_FLAG_BACKUP_SEMANTICS) OK
Resolve NT path GetFinalPathNameByHandleW(VOLUME_NAME_NT) OK (\Device\HarddiskVolumeN\…)
Resolve DOS path GetFinalPathNameByHandleW(VOLUME_NAME_DOS) FAIL — Access denied (needs \GLOBAL??\C:)

So the dir open succeeds and NT-path resolution succeeds; only the DOS drive-letter resolution (which
std::fs::canonicalize uses) is denied. Plain std::fs::read/write on the same dir work — they don't do the
\GLOBAL?? resolution, so only canonicalize trips it.

The offending call is codex-rs/core/src/config.rs, find_codex_home():

pub fn find_codex_home() -> std::io::Result<PathBuf> {
    if let Ok(val) = std::env::var("CODEX_HOME") {
        if !val.is_empty() {
            return PathBuf::from(val).canonicalize();   // <-- fails inside an AppContainer
        }
    }
    // ... (the unset branch does not canonicalize)
}

Proposed fix (one-liner, no behavior change on normal setups)

Don't hard-fail on canonicalize; fall back to a pure-string absolutization that opens no handle and does no
\GLOBAL?? resolution. This is the well-established try_canonicalize pattern (used by cargo/rustc for exactly this
class of Windows/sandbox canonicalize unreliability — see rust-lang/rust#79449, cargo#11866, std::path::absolute
rust-lang/rust#91673):

if let Ok(val) = std::env::var("CODEX_HOME") {
    if !val.is_empty() {
        let p = PathBuf::from(val);
        // canonicalize() opens a handle + resolves the DOS drive letter via \GLOBAL??, which a
        // Windows AppContainer/lowbox token is denied. Fall back to a pure-string absolute path
        // (GetFullPathNameW on Windows) so CODEX_HOME works inside a sandbox.
        return p.canonicalize().or_else(|_| std::path::absolute(&p));
    }
}

std::path::absolute (stable since 1.79) is GetFullPathNameW-based on Windows — no directory handle, no object-
namespace lookup — so it succeeds in the AppContainer while remaining a no-op-equivalent for already-absolute paths on
normal setups. (If std::path::absolute isn't desired, dunce::canonicalize or a manual GetFullPathNameW are
equivalents; the key point is: don't require a handle-opening canonicalize on CODEX_HOME.)

Repro (Windows 11)

  1. Create an AppContainer profile (CreateAppContainerProfile) → package SID.
  2. Make a dir (e.g. C:\codex-home-test) and grant that package SID Full (so the process can read/write it), seed a
    normal ~/.codex into it, set CODEX_HOME to it.
  3. Launch codex login status in the AppContainer via CreateProcess + PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES.
  4. Observe the failed to canonicalize CODEX_HOME … Access is denied (os error 5) error, despite the process being
    able to read/write the dir. GetFinalPathNameByHandleW(VOLUME_NAME_NT) on the same handle succeeds; VOLUME_NAME_DOS
    fails.

Related

  • Ties to the Codex Windows sandbox ACL/Error-5 issues (e.g. #13378 — the sandbox setup failing to establish drive-root
    access). This is the path-resolution counterpart: even with directory ACLs correct, canonicalize on CODEX_HOME
    fails on the \GLOBAL?? DOS-drive-letter step.

Environment

  • Windows 11 (10.0.22631), codex CLI (Rust), running inside a per-agent AppContainer (lowbox token).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in codex-rs/core/src/config.rs at find_codex_home() and inspect the CODEX_HOME branch that calls canonicalize(). Reproduce or verify behavior with CODEX_HOME inside a Windows AppContainer, then confirm the fallback permits startup without DOS-drive-letter resolution while preserving normal behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, operating-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.