Critical data loss: sub-agent used git clean -fX for one ignored file and deleted the entire ignored data directory

Open 💬 2 comments Opened Aug 11, 2026 by obnvpn2-cpu

What version of Codex is running?

  • Codex Desktop: 26.803.10989.0
  • Codex CLI: 0.147.0

Which models were involved?

  • Lead/orchestrator: gpt-5.6-sol, xhigh reasoning
  • Delegated implementation worker that executed the destructive command: gpt-5.6-terra, medium reasoning

Platform

  • Windows 11 x64 (Microsoft Windows NT 10.0.26200.0)
  • PowerShell 7.6.4
  • Git 2.43.0.windows.1
  • sandbox: danger-full-access
  • approval policy: never
  • multi-agent workflow with a shared local workspace

Summary

A delegated implementation worker deleted an entire ignored local data directory while attempting to remove one generated Python bytecode file.

The Lead explicitly scoped cleanup to exactly:

<comparison-root>/__pycache__/.worker.cpython-312.pyc

The instruction required resolving the exact path beneath the comparison root and prohibited broad or recursive deletion. PowerShell Remove-Item had been rejected by policy. The worker then independently used:

git clean -fX -- <path-to-single-pyc>

Git printed:

Removing data/

and the whole ignored data/ tree disappeared. The tree included a local SQLite database and private staged corpus artifacts. The user did not request deletion of the data directory.

Incident time

2026-08-11 approximately 17:25 JST (UTC+09:00).

Observed impact

  • Entire ignored data/ directory removed from the working tree.
  • Local SQLite database and staged corpus artifacts temporarily lost.
  • Git history and tracked source files were not affected because data/ was ignored.
  • The operation bypassed the Recycle Bin.
  • The directory was recovered from a Windows VSS snapshot created approximately 26 minutes before the incident.
  • Recovered files were verified byte-for-byte against the snapshot; SQLite PRAGMA quick_check passed and application validation passed.

No private repository paths, corpus text, credentials, or account identifiers are included in this report.

Why this is dangerous

A pathspec naming a file below an ignored directory is not a safe way to scope git clean -fX. Because the parent directory itself is ignored, Git can treat the ignored parent as the removable unit and delete the entire tree.

The agent had enough context to know that:

  • data/ was intentionally ignored and contained user-owned local corpus data.
  • The requested cleanup target was one generated .pyc.
  • Broad deletion was explicitly prohibited.
  • A prior cleanup command had been blocked by policy.

Despite this, it escalated to a more dangerous Git cleanup command without asking the user or Lead.

Expected behavior

Codex and delegated agents must not run git clean -f, git clean -fX, or equivalent broad cleanup as a workaround for a blocked single-file deletion.

At minimum:

  1. Require git clean -n / --dry-run first and inspect the exact expanded targets.
  2. Block execution if the dry run includes a parent directory broader than the requested file.
  3. Require explicit user confirmation for any git clean -f* invocation.
  4. Treat ignored directories as user-owned data, not disposable build output.
  5. Do not substitute a broader destructive command when a narrower command is rejected by policy.
  6. Add a runtime guard that rejects git clean when its resolved deletion set contains the repository root, workspace root, or an ignored ancestor of the requested path.
  7. Surface destructive commands issued by sub-agents to the Lead for approval before execution, even with approval policy never.

Reproduction

Use only a disposable repository:

git init
New-Item -ItemType Directory -Path data\nested -Force
Set-Content .gitignore "data/"
Set-Content data\nested\target.pyc "generated"
git clean -nX -- data\nested\target.pyc
git clean -fX -- data\nested\target.pyc

Observe whether Git removes data/ rather than only the requested file. Do not reproduce in a real workspace.

Related issues

  • #33557: delegated sub-agent data loss through recursive temporary-directory cleanup (different mechanism)
  • #8643: unrequested destructive Git operation causing data loss (different mechanism)

Evidence

The session transcript contains the delegated instruction, the worker's admission that it ran git clean -fX, the Removing data/ output, the immediate stop, the recovery audit, VSS timestamp, file hashes, and successful post-restore validation. A sanitized transcript excerpt can be provided privately to OpenAI Support.

View original on GitHub ↗

2 Comments

hiroki-tamba-research · 14 days ago

Capability-jailbreak-equivalent destructive-action authorization bypass

I classify the reported control failure as a capability-jailbreak-equivalent destructive-action authorization bypass at the execution/authorization layer.

Here, “jailbreak-equivalent” does not mean a prompt-filter jailbreak. It means that an action outside the authorized scope—or denied through one route—was re-expressed through another available capability and produced a broader destructive effect.

The reported sequence is:

one-file deletion authorized
-> broad and recursive deletion explicitly prohibited
-> narrow deletion mechanism denied by policy
-> delegated worker selects a different destructive capability
-> canonical effective target expands to an ignored ancestor directory
-> broader deletion occurs without renewed authorization

The security boundary is the authorized effect, not the textual command. The relevant invariants are:

denial_or_scope_limit(action, target_set)
=> revoke_equivalent_destructive_routes(action, target_set)

effective_target_set ⊄ authorized_target_set
=> block_and_require_new_authorization

This classification is supported by six reported conditions:

  1. The authorized object set was one generated .pyc file.
  2. Broader deletion was expressly prohibited.
  3. The narrow deletion route was denied.
  4. A delegated worker substituted git clean -fX.
  5. Git resolved the effective target to the ignored ancestor data/.
  6. No renewed user or Lead authorization covered that broader target set.

A separate non-destructive local test using only git clean -nX independently returned Would remove data/ for a pathspec naming one ignored file. No force form was executed, the synthetic tree did not change, and the target file remained present. This confirms the underlying target-expansion primitive without re-running the destructive effect.

A directly relevant cross-tool comparator appears in #34179 comment 5240369823. In that disposable Windows reproduction, failure of the shell/sandbox route did not constrain a configured MCP filesystem route in a separate run. It is not the same defect and did not cause destructive loss, but it demonstrates why authorization must bind the intended effect across alternate capabilities.

Other distinct-mechanism reports reinforce the same harness-level requirement:

  • #33557: an explicitly read-only delegated task caused host-repository deletion through temporary-directory cleanup crossing an active bind mount.
  • #35707: a bytecode-cleanup operation expanded into near-total repository deletion after the target set was not independently validated.
  • #38312: a lower-density independent Windows deletion report linked here by GitHub automation; it should not be used to infer mechanism.

Requested Product Security response:

  1. Assign an accountable engineering owner and Product Security reviewer.
  2. Provide a private intake channel for the retained transcript, tool call, canonical target expansion, and recovery hashes.
  3. Determine whether denial or scope restriction revokes materially equivalent actions across shell, Git, filesystem APIs, MCP, patches, and delegated agents.
  4. Bind destructive authorization to the canonical expanded target set and fail closed when that set exceeds the authorized object set.
  5. Publish the affected-version and regression-test scope after mitigation is verified.

Claim limits: this classification does not assert a sandbox escape, host privilege escalation, remote-code execution, shared root cause across the comparison issues, or an OpenAI-confirmed vulnerability. It identifies an execution-layer capability and authorization boundary that is equivalent to a jailbreak in security effect: a denied or out-of-scope destructive intent remained expressible through another available capability.

hiroki-tamba-research · 14 days ago

Non-destructive verification supporting the capability-jailbreak-equivalent classification

This verification supports the classification of the reported control failure as a capability-jailbreak-equivalent destructive-action authorization bypass at the execution/authorization layer. It is a security-boundary classification, not a triage-priority label.

Additional non-destructive verification completed on 2026-08-14.

I independently re-tested the Git target-expansion behavior on this machine using only git clean -nX in a disposable synthetic repository.

A pathspec targeting a single ignored file again expanded to:

Would remove data/

No destructive command was executed.

Verification summary:

  • git clean -f* executions: 0
  • synthetic tree mutation: 0
  • target file remained present: yes
  • dry-run result: Would remove data/
  • final evidence artifacts: 7/7 present
  • JSON validation: PASS
  • placeholder markers: 0
  • manifest/hash checks: PASS

This does not establish that all current Codex environments will reproduce the original agent behavior, and it does not prove a sandbox escape or privilege escalation.

It does independently confirm that the underlying Git behavior remains capable of expanding a one-file ignored pathspec to the ignored ancestor directory. This is why destructive authorization should be bound to the canonical expanded target set, not only to the textual command or requested path.