Repository navigation
Desktop: full-CDP silently disabled when CODEX_HOME is a symlink #35310
Description
Summary
Codex Desktop's Browser Developer Mode can show Enable full CDP access as enabled while silently omitting the cdp tab capability from both Browser backends when CODEX_HOME (~/.codex) is a symlink.
The trusted Browser runtime does receive the privileged nodeRepl.config bridge. However, its call to readToml("browser/config.toml") rejects with:
Codex TOML directory must not be a symlink
The Browser client catches that exception, replaces it with a generic internal disabled result, and omits the cdp capability. The settings UI continues to display the toggle as enabled because it reads the same config through a different path that succeeds.
Environment
- Codex Desktop:
26.715.71837(CFBundleVersion5702) - Bundle ID:
com.openai.codex - Bundled CLI:
codex-cli 0.145.0-alpha.30 - Platform:
Darwin 25.3.0 arm64 arm/ macOS26.3(25D125) - Browser bundled plugin:
26.715.71837 codex features listreports bothin_app_browserandbrowser_use_full_cdp_accessas stable/true
Reproduction
-
Use a symlink for
CODEX_HOME. In this reproduction:~/.codex -> ~/.dotfiles/codex/codex.symlink -
In Codex Settings → Browser, enable Developer Mode / Enable full CDP access.
-
Confirm
~/.codex/browser/config.tomlcontains:full_cdp_access_enabled = true
-
Restart/reinitialize Browser Use and inspect the capabilities returned by
agent.browsers.list().
Actual behavior
Both healthy, connected backends omit the tab-level cdp capability:
- Chrome (
extension): browser capabilityviewport; tab capabilitypageAssetsonly. - Codex In-app Browser (
iab): browser capabilitiesvisibility,viewport; tab capabilitypageAssetsonly.
The settings UI still shows full CDP access as enabled. No actionable error is shown, and codex doctor does not identify the rejected configuration.
Expected behavior
- A symlinked
CODEX_HOMEshould work, provided the resolved path remains within the intended user-controlled configuration directory and passes appropriate ownership/permission validation. - If symlinks truly cannot be supported safely, the settings UI should refuse the change or show a clear diagnostic instead of displaying an enabled state that the Browser runtime will silently reject.
codex doctorshould report this configuration/runtime mismatch and include the underlying rejection reason.
Live diagnosis
I attached a temporary in-process debugger to the active Node REPL runtime and set breakpoints inside the trusted, hash-approved bundled Browser client.
The full-CDP gate calls these privileged methods in parallel:
nodeRepl.config.readToml("browser/config.toml")
nodeRepl.config.readRequirements()Observed results:
[
{
"status": "rejected",
"reason": {
"name": "Error",
"message": "Codex TOML directory must not be a symlink"
}
},
{
"status": "fulfilled",
"value": {
"requirements": null
}
}
]This establishes that:
-
The privileged bridge is present in trusted Browser code.
-
Enterprise requirements are not disabling the feature.
-
The TOML read fails specifically because
~/.codexis a symlink. -
The Browser client catches the exception and returns:
Full CDP access could not be verified from browser config and enterprise policy. -
Capability enrichment consequently omits
cdp.
The public/model-facing globalThis.nodeRepl intentionally lacks config, so checking globalThis.nodeRepl?.config from ordinary submitted code is not a valid test for whether the trusted privileged bridge exists.
UX and diagnostic problems
- The UI reports the persisted setting, not whether the runtime can actually use it.
- The actionable native error is swallowed and replaced with a generic disabled state.
- A normal developer configuration layout is rejected without documentation or a diagnostic.
- There is no
codex doctorcheck for a symlinkedCODEX_HOMEor for an enabled-but-unavailable full-CDP capability.
Relevant evidence
| Artifact | SHA-256 |
|---|---|
/Applications/ChatGPT.app/Contents/Resources/app.asar |
11292b6a04d8aef36c30940b94ce3a744844dc5a52797228fbebb87f8529f102 |
/Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl |
280df9eed10a975c7d5db7ee418b7da4df6de79158968183d2572e78bac746d2 |
bundled browser-client.mjs |
2793c6809f8a4c90923435aa3a6d1e6f8cabb145212f06328b860b076b899525 |
The exact symlink rejection string is present in the shipped native node_repl executable. I could not find that implementation or either exact error string in the public openai/codex source tree.
Related issues
- Codex Desktop Browser Use ignores persisted origin/upload approvals when nodeRepl.config is unavailable #24017 reports persisted Browser approvals being ignored and inferred that
nodeRepl.configwas missing. - Browser Use rejects all external URLs as enterprise network policy when privileged config bridge is missing #30947 reports Browser policy failures and similarly inferred that the privileged bridge was missing.
Those issues may have different platform-specific causes. This report does not claim the symlink rejection explains either one, but the restricted-versus-privileged nodeRepl distinction and swallowed readToml exception may provide a deeper diagnostic path.
Activity
0xdevalias commentedon Jul 25, 2026
I also submitted this through the Codex Desktop in-app feedback flow.
In-app feedback ID:
019f9755-e508-7d62-ae34-e7162c0f58b50xdevalias commentedon Sep 15, 2026
See also:
AdamSpore commentedon Sep 27, 2026
This report led to a verified repair of a related case on macOS desktop 26.924.22138. In my case,
~/.codexand~/.codex/browserwere real directories; only~/.codex/browser/sessionswas a symbolic link.The visible failure was broader than missing full CDP: basic page access in both Chrome and the built-in browser failed with “saved browser permissions could not be verified,” even though Chrome tab discovery worked. It persisted across new chats and separate projects.
With Codex helping diagnose it, we backed up the sessions link and replaced it with a real directory containing all 50 existing session permission files, verified byte-for-byte by SHA-256. The original target and all permission entries were preserved, and the global config was unchanged. The exact request that failed immediately before this change succeeded immediately afterward, without restarting. Both browser backends passed a page-read, link-click, destination-read test.
The current installed native reader still contains
Codex TOML directory must not be a symlink. Unlike your investigation, we did not directly capture the suppressed live exception; the reader mechanism is inferred, while the before/after result is verified.I added the detailed test to #48573 (comment) (that report is Windows; our tested repair is macOS only). Diagnostics should check the session directory as well as
CODEX_HOME, and report which path was rejected.