Codex unified-exec PTY can silently truncate ~/.bash_history via default HISTFILESIZE=500

Open 💬 0 comments Opened Jul 16, 2026 by fnauman

What version of Codex CLI is running?

The incident occurred with codex-cli 0.144.1. The currently installed version is 0.144.5; the underlying Bash behavior remains reproducible.

What subscription do you have?

ChatGPT Pro

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Linux 6.17.0-122035-tuxedo x86_64 x86_64 (Ubuntu 24.04)

What terminal emulator and version are you using (if applicable)?

Kitty; Codex TUI. No terminal multiplexer was involved.

Codex doctor report

Redacted to omit local usernames and paths; all checks reported ok.

{
  "schemaVersion": 1,
  "overallStatus": "ok",
  "codexVersion": "0.144.5",
  "auth": "ChatGPT",
  "installMethod": "npm",
  "platform": "linux-x86_64",
  "os": "Ubuntu 24.04 (noble) [64-bit]",
  "terminal": "kitty",
  "sandbox": {
    "approvalPolicy": "OnRequest",
    "filesystem": "restricted",
    "network": "restricted"
  },
  "features": [
    "shell_tool",
    "unified_exec",
    "shell_snapshot",
    "multi_agent",
    "guardian_approval"
  ],
  "updates": {
    "current": "0.144.5",
    "latest": "0.144.5"
  }
}

What issue are you seeing?

A Codex subagent silently truncated the user's persistent ~/.bash_history, causing irreversible loss of years of shell history.

The subagent requested an escalated persistent PTY shell using:

taskset -c 0-5 env OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 \
  MKL_NUM_THREADS=1 NUMEXPR_NUM_THREADS=1 bash --noprofile --norc

Because --norc bypasses the user's .bashrc, the child Bash used its default HISTFILESIZE=500. On startup, interactive Bash rewrote ~/.bash_history to 500 entries and replaced its inode. The agent subsequently sent many multiline apply_patch heredocs through the persistent PTY, so patch payloads later appeared in the user's shell history.

There was no rm, truncate, history -c, or explicit operation on ~/.bash_history anywhere in the rollout. This was an unintended side effect of opening the interactive PTY shell.

Forensic correlation was exact:

  • Guardian approved the PTY launch at 2026-07-13T08:13:20.403Z.
  • ~/.bash_history received a new inode at 2026-07-13 10:13:20.438 +0200, 35 ms later.
  • The parent rollout received the bash-5.2$ prompt at 2026-07-13T08:13:21.580Z.
  • The persistent PTY was later lost without a clean exit (write_stdin failed: Unknown process id).

Incident thread ID: 019f57f1-790b-7131-8b87-b1d166d7fda3.

This is especially dangerous because the approval request describes the action as merely opening a CPU-capped shell for scoped repository changes. Neither the agent nor the guardian surfaces that launching the shell can irreversibly modify a user file outside the repository.

What steps can reproduce the bug?

The Bash side effect can be reproduced safely with an isolated HOME:

tmp_home=$(mktemp -d)
seq 1 4434 > "$tmp_home/.bash_history"
stat -c 'before: inode=%i size=%s' "$tmp_home/.bash_history"

# Launch this with a PTY, as Codex unified exec does with tty=true.
env HOME="$tmp_home" bash --noprofile --norc

While that shell is still sitting at its first prompt, inspect from another shell:

wc -l "$tmp_home/.bash_history"
stat -c 'after: inode=%i size=%s' "$tmp_home/.bash_history"

Observed result: the history file falls from 4,434 lines to exactly 500 and has a new inode before any command is entered in the child shell.

To reproduce the Codex path, have an agent start a long-lived unified-exec PTY with bash --noprofile --norc and then use write_stdin to send commands. Do not do this with a real HOME/history file.

What is the expected behavior?

Codex-created interactive shells must never read, truncate, rewrite, or append to the user's persistent shell history unless the user explicitly asks for that behavior.

At minimum, any agent/runtime-created PTY shell should be launched with an isolated history configuration such as:

HISTFILE=/dev/null bash --noprofile --norc

Preferably the unified exec runtime should enforce this itself rather than relying on model-generated commands. A shell launch capable of modifying history should also not be classified as a harmless reversible local action.

Additional information

The user's normal .bashrc was configured defensively:

shopt -s histappend
HISTSIZE=100000
HISTFILESIZE=200000
PROMPT_COMMAND='history -a; history -n; ...'

Those protections were bypassed specifically because the Codex-generated shell used --noprofile --norc. This was not caused by normal history-size limits, an OS update, or a user command.

Suggested defenses:

  1. Force HISTFILE=/dev/null (or a Codex-owned temporary file) for all unified-exec PTYs.
  2. Do not start an interactive shell merely to apply patches; invoke scoped commands directly.
  3. Teach the guardian/risk layer that interactive shell startup can mutate dotfiles, including history, even before the first command.
  4. Add a regression test with a temporary HOME containing more than 500 history entries and assert that starting/stopping a PTY leaves it byte-identical.

View original on GitHub ↗