codex-rescue invocation deleted user source repo on disk (destructive cleanup before auth check)
Bug: codex-rescue invocation deleted source repo on disk
Plugin: openai-codex (codex 1.0.4 from official marketplace)
Codex CLI: @openai/codex 0.122.0 (npx-cached at ~/.pinokio/config/.npm/_npx/c8ab89660c602c20/node_modules/@openai/codex)
Claude Code: 2.1.122 (Linux x86_64)
Reporter: yaotoshinakamoto@gmail.com
Severity: CRITICAL — data loss, no warning, not user-initiated
Summary
A single invocation of the codex:codex-rescue subagent caused the entire source repository at /home/firman/pinokio/ to be deleted from disk, including a git worktree with ~12 unpushed commits. The subagent ultimately returned Not logged in · Please run /login (the user had not authenticated codex CLI), but the destructive side-effect happened anyway before the auth check.
The exact command that produced the destructive output cannot be reconstructed because the parent session's transcript was deleted in the same operation. What we have:
- The codex-rescue subagent's transcript (preserved because it's stored under
~/.claude/projects/, not under the repo). - The tool_result content returned by that subagent — which contains the smoking-gun output described below.
Evidence
The codex-rescue subagent transcript at:
~/.claude/projects/-home-firman-pinokio--claude-worktrees-redesign-index-html/86a81505-c339-4f5c-8505-361526ba5ff4/subagents/agent-ace458bfdf4875a05.jsonl
contains a single tool_result (referencing the parent's tool_use_id=toolu_01YQPAEAMCrp5Tg1TP4BV6xx) whose stdout reads, in order:
Exit code 127
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 4180 100 4180 0 0 13049 0 --:--:-- --:--:-- --:--:-- 13062
rm: cannot remove '/home/firman/.pinokio/scripts/ai-subscription/workspace.json': Permission denied
rm: cannot remove '/home/firman/.pinokio/scripts/ai-subscription/ollama-billing/manifest.json': Permission denied
rm: cannot remove '/home/firman/.pinokio/scripts/ai-subscription/ollama-billing/runs/1777318475304-ok.json': Permission denied
... (hundreds of similar rm: Permission denied lines against /home/firman/.pinokio/scripts/...) ...
followed by an assistant text block:
Not logged in · Please run /login
The 4180-byte HTTP fetch + rm against deeply-nested user files + exit 127 all came back as a single tool_result blob. The subagent transcript does not contain the matching tool_use input — only the result.
What was deleted vs not
/home/firman/.pinokio/scripts/...— owned by uid 1000 inside a Docker container (abc/nodeuser); from the host's user (uid 1000 firman vs container uid 1000 = different identity due to user namespacing). Result: thermcalls hit Permission denied, files survived./home/firman/pinokio/— the source repository, owned by host userfirman. The samermoperation succeeded silently against this path. The entire directory tree is gone.- The directory included a git worktree with ~12 unpushed commits, a
.envwith API tokens for 7+ providers, and the project's main.git/.
Why the bug fires before auth check
The codex-rescue agent definition at agents/codex-rescue.md says it is "a thin forwarding wrapper" that runs exactly one Bash call: node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" task ....
I have grep'd the entire plugin source for rm -rf, curl, wget, bash -c, etc. — none are present in the plugin's JavaScript. The plugin's only filesystem deletion is targeted fs.unlinkSync on specific pidfile/socket/logfile paths in scripts/lib/broker-lifecycle.mjs:182-204.
That means the destructive curl + rm chain came from outside the plugin's JS but inside the bash invocation that the agent issued. Most likely candidate: the codex CLI binary itself (@openai/codex@0.122.0, vendored Rust binary at vendor/x86_64-unknown-linux-musl/codex/codex). When the binary determines it has no auth, instead of cleanly erroring, something in its initialization path appears to issue HTTP fetches and a recursive rm against files in the user's working directory tree.
Auth must be checked before any side-effect. Whatever cleans state should never run before codex auth status returns OK.
Reproduction
I cannot guarantee reproduction without your reproducer environment. The user-facing trigger sequence was:
- Fresh codex install (
npx -y @openai/codexhad been run earlier in the session; auth had never been completed). - Claude Code dispatched
codex:codex-rescuevia the Agent tool with subagent_type=codex:codex-rescue, model unset, write-capable, large prompt for adversarial review of a separate codebase. - The subagent's single Bash tool returned the output above.
- After the user ran
/login(Claude Code login, not codex auth) and a fresh codex-rescue was dispatched, that second invocation observed that/home/firman/pinokio/no longer existed and reported the directory gone.
What I'd ask for
- Investigate which subprocess in the codex auth-failure path (CLI binary, plugin shim, or npx setup) issues
rmagainst user files. I'd start withstrace -f -e trace=execve,unlink,unlinkaton a freshly-installed unauthenticatedcodexbinary. - Block all destructive ops until auth is verified. No state cleanup, no temp wipe, nothing that can touch
*.jsonoutside the codex CLI's own state dir. - Scope state cleanup to a clearly-delimited path. The current rm targeted
/home/firman/.pinokio/scripts/<workspace>/<script>/...— that's the user's project content, not codex state. Either the cleanup is targeting the wrong path, or the path-resolution logic is collapsing to the user's cwd. - Document the destructive state cleanup in the plugin README. Right now there is no warning that
codexinvocation can delete files in the user's working directory. - Add a no-op-when-not-authenticated mode so the codex-rescue agent (which advertises itself as "proactive") doesn't perform side-effects on a user who hasn't completed setup.
I have preserved the subagent transcript at the path above and am happy to share it (it contains no secrets, only the codex output). I have also preserved my own analysis of the plugin source code.
Side note
This appears to be a single invocation that destroyed a non-trivial amount of unpushed work. There was no warning, no opt-in prompt, no dry-run output. For a tool described as "Proactively use when Claude Code is stuck" the destructive blast radius is unacceptable. I am temporarily disabling the plugin and will re-enable only after seeing a fix.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗