Standalone updater can overwrite managed Codex with a self-referential symlink when CODEX_INSTALL_DIR points to standalone/current/bin
What version of Codex CLI is running?
The failure occurred while a 0.144.2 managed updater was installing 0.144.3.
It is also reproducible directly with the current standalone installer resolving Codex CLI 0.144.3.
What platform is your computer?
macOS, Apple Silicon.
Observed on two separate Macs and reproduced in an isolated temporary HOME.
What issue are you seeing?
If CODEX_INSTALL_DIR points to the managed standalone command directory:
$HOME/.codex/packages/standalone/current/bin
the standalone installer overwrites the managed codex binary with a
self-referential symbolic link:
current/bin/codex ->
current/bin/codex
The release binary reached through standalone/current is also corrupted.
When this environment variable is inherited by:
codex app-server daemon pid-update-loop
the installation may initially work, then break during the daemon updater's
first or subsequent update cycle. Remote clients subsequently report that the
Codex CLI is not installed.
Minimal reproduction
This uses an isolated temporary HOME and does not modify the user's real Codex
installation:
REPRO_HOME="$(mktemp -d)"
curl -fsSL https://chatgpt.com/codex/install.sh |
env -i \
HOME="$REPRO_HOME" \
PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
CODEX_HOME="$REPRO_HOME/.codex" \
CODEX_INSTALL_DIR="$REPRO_HOME/.codex/packages/standalone/current/bin" \
CODEX_NON_INTERACTIVE=true \
/bin/sh
Actual behavior
The installer exits with:
==> Installing standalone package to .../.codex/packages/standalone/releases/0.144.3-aarch64-apple-darwin
/bin/sh: .../standalone/current/bin/codex: Too many levels of symbolic links
Afterward:
readlink "$REPRO_HOME/.codex/packages/standalone/current/bin/codex"
returns the exact same path:
.../.codex/packages/standalone/current/bin/codex
Expected behavior
The installer should reject a CODEX_INSTALL_DIR that points inside the
managed standalone/current tree, rather than replacing the managed binary.
The daemon updater should also avoid inheriting installer-affecting environment
variables such as CODEX_INSTALL_DIR, or explicitly sanitize them before
invoking install.sh.
Why this matters
The app-server daemon update loop invokes the standalone installer
automatically after an initial delay and then periodically:
https://github.com/openai/codex/blob/main/codex-rs/app-server-daemon/src/update_loop.rs
Because the spawned shell inherits the updater environment, a persistentCODEX_INSTALL_DIR can silently corrupt an otherwise working managed
installation later.
A related Windows report also shows the standalone updater being affected by
inherited shell environment:
https://github.com/openai/codex/issues/27117
Possible fixes
- Canonicalize and compare the visible command path with the managed binary
path before creating the symlink.
- Reject
CODEX_INSTALL_DIRvalues located insidestandalone/currentor its
active release.
- Remove
CODEX_INSTALL_DIRfrom the daemon updater child's environment. - Add a regression test covering this self-referential destination.