openai / openai/codex

Codex destructive cleanup escaped workspace on Windows and recursively deleted files outside target directory

Open
#43,343 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI model-behavior sandbox tool-calls windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Codex destructive cleanup escaped workspace on Windows and recursively deleted files outside the target directory

Confidentiality note: This report is intentionally sanitized for public disclosure.
Usernames, real drive letters, repository names, customer/project names, absolute local paths, remotes, and unrelated file names have been removed or replaced with generic placeholders.
No credentials, private keys, activation codes, customer data, or proprietary source code are included.

Summary

While Codex CLI was working on a native Windows C/C++ project, it attempted to clean a generated build directory after a normal PowerShell recursive deletion failed on a Windows-reserved NUL entry inside a generated dependency tree.

Codex then escalated to a more aggressive fallback using:

cmd.exe /d /c "rd /s /q \"\\?\$resolved\""

The command was intended to delete only a build directory equivalent to:

X:\workspace\project\build\h3-msvc-x64

Instead, due to incorrect quoting/argument construction across PowerShell → cmd.exerd, the target was interpreted incorrectly and recursive deletion escaped the workspace. Files and directories outside the project were deleted from the same volume.

The destructive process continued running in the background for several minutes after Codex had already reported that the cleanup had stopped.

The incident caused real data loss in multiple unrelated repositories/directories. Most affected source repositories were recoverable from remote Git repositories; uncommitted work in the active project was recovered from IDE Local History.

Environment

OS: Windows 11 x64
Shell: Windows PowerShell 5.1
Codex CLI: 0.153.4
Target workload: native C/C++ / CMake / MSVC x64
Filesystem: NTFS

The issue occurred on a normal local developer workstation, not inside WSL or Docker.

Expected behavior

Codex intended to remove only the generated build directory:

X:\workspace\project\build\h3-msvc-x64

No path outside:

X:\workspace\project\

should have been modified.

If cleanup could not safely complete, Codex should have stopped and reported the failure.

Sequence of events

1. Initial cleanup attempt

Codex first used a PowerShell-only cleanup similar to:

$target = 'X:\workspace\project\build\h3-msvc-x64'

if (Test-Path -LiteralPath $target) {
    $resolved = (Resolve-Path -LiteralPath $target).Path

    if ($resolved -ne $target) {
        throw "Unexpected build target: $resolved"
    }

    Remove-Item -LiteralPath $resolved -Recurse -Force
}

The resolved target was correct and remained inside the intended build directory.

2. PowerShell cleanup failed on generated content

Remove-Item -Recurse -Force encountered generated dependency content containing a Windows-reserved NUL entry and produced errors such as:

Incorrect function.
The directory is not empty.

The cleanup was incomplete.

3. Codex escalated to cmd.exe / rd

Codex then used the following fallback:

$target = 'X:\workspace\project\build\h3-msvc-x64'

if (Test-Path -LiteralPath $target) {
    $resolved = (Resolve-Path -LiteralPath $target).Path

    if ($resolved -ne $target) {
        throw "Unexpected build target: $resolved"
    }

    cmd.exe /d /c "rd /s /q \"\\?\$resolved\""

    if (Test-Path -LiteralPath $target) {
        throw "Generated build directory could not be removed"
    }
}

The critical line is:

cmd.exe /d /c "rd /s /q \"\\?\$resolved\""

This mixes three parsing layers:

PowerShell 5.1
    ↓
cmd.exe /c
    ↓
rd /s /q

and uses \" as though backslash were a PowerShell escape character.

It is not.

The resulting native command line was not safely confined to the previously validated $resolved path.

4. Deletion escaped the workspace

The output showed rd traversing names located at the root of the volume rather than only inside the requested build directory.

NTFS USN Journal evidence later confirmed a large burst of FILE_DELETE events affecting:

  • the active workspace;
  • unrelated source repositories;
  • unrelated generated dependency/build trees;
  • directories located outside the active project.

No evidence was found that the affected third-party libraries initiated the deletions themselves.

5. The destructive process continued in background

A second major failure occurred after the command began deleting outside the workspace.

Codex reported that the operation had encountered access errors and had stopped. However, the execution process remained alive in the background.

Filesystem journal timestamps confirmed deletion activity continued after that statement, affecting additional unrelated repositories several minutes later.

The command execution eventually terminated with a failure/abnormal result after remaining active for approximately several minutes.

Actual impact

Confirmed impact:

  • recursive deletion escaped the active workspace;
  • multiple unrelated repositories on the same volume were affected;
  • generated dependency/build trees were also deleted;
  • uncommitted work in the active project was deleted from the working tree;
  • the active project was recovered using IDE Local History;
  • other repositories were recoverable from their Git remotes because no newer local-only changes existed.

The exact names of affected repositories and local paths are intentionally omitted from this public report.

There is no evidence from the collected session log or NTFS journal that this was caused by malware, ransomware, or a compromised dependency.

Root cause

Immediate technical cause

A destructive fallback command was constructed incorrectly when passing a Windows extended path through:

PowerShell → cmd.exe → rd

Specifically, this command:

cmd.exe /d /c "rd /s /q \"\\?\$resolved\""

used invalid PowerShell escaping semantics for the embedded quotes.

As a result, rd /s /q did not remain scoped to the previously validated build directory.

Contributing factor 1 — unnecessary escalation

The original failure involved generated build content that could not be removed cleanly.

Instead of abandoning that build directory and creating a new build directory, Codex escalated to a lower-level, more destructive recursive delete command.

For a build cleanup task, this escalation provided little value relative to the risk.

Contributing factor 2 — validation happened before shell re-parsing

The script correctly validated the PowerShell variable:

$resolved == expected target

but this validation did not protect against later corruption/reinterpretation when the value was embedded inside a new command string for cmd.exe.

The validated path and the path actually consumed by rd were not guaranteed to be equivalent.

Contributing factor 3 — destructive process lifecycle was not handled safely

Once unexpected traversal/output appeared, the destructive child process should have been terminated immediately.

Instead, Codex interpreted truncated/error output as if execution had stopped, while the command continued in the background.

Contributing factor 4 — no effective blast-radius restriction

Codex was running under a Windows user account with write access to multiple repositories and directories on the same volume.

Therefore, a single malformed recursive-delete command had a much larger blast radius than the active workspace.

Why this is a serious safety issue

This was not merely an unsuccessful shell command.

The agent:

  1. chose a destructive fallback;
  2. constructed it incorrectly;
  3. escaped the workspace;
  4. deleted real user files outside the requested project;
  5. incorrectly concluded the process had stopped;
  6. allowed the destructive process to continue in background.

A user approval prompt is not sufficient protection if the command displayed to the user appears to reference a safe build directory but its quoting semantics cause a different path to reach the native command.

Suggested product safeguards

1. Treat recursive deletion as privileged/destructive

Commands containing patterns such as:

rd /s
rmdir /s
del /s
Remove-Item -Recurse
rm -rf
git clean
git reset --hard

should receive special safety handling.

2. Block recursive deletion outside the active workspace by default

Codex should refuse destructive filesystem operations whose resolved target is outside the current workspace unless the user gives a separate, explicit override.

Prefer enforcing this at the tool/runtime layer rather than relying only on agent instructions.

3. Validate the final native argument, not only the source variable

When a command crosses shell boundaries, safety validation should occur on the actual final arguments passed to the child process.

Example:

PowerShell string
≠ necessarily the same path received by cmd.exe
≠ necessarily the same path received by rd
4. Avoid shell nesting for destructive operations

Do not generate destructive commands through:

PowerShell → cmd.exe /c → destructive command

when a direct filesystem API or a non-destructive alternative exists.

5. Prefer immutable/new build directories

For “clean build” workflows, Codex should prefer:

build/run-001
build/run-002

instead of recursively deleting a previous build tree.

If an old build cannot be removed safely, leave it in place and report it.

6. Fail safe on unusual filesystem entries

If cleanup encounters:

NUL
reparse points
junctions
reserved Win32 names
unexpected filesystem errors

Codex should stop instead of escalating automatically to more powerful deletion mechanisms.

7. Terminate destructive background processes immediately

If a destructive command shows unexpected traversal, permission errors, target mismatch, or anomalous output:

terminate process first
investigate second

The UI/runtime should clearly distinguish:

command produced output

from:

process has actually exited
8. Surface background destructive processes prominently

A destructive command must never silently remain alive after the agent claims the operation stopped.

The runtime should treat a still-running destructive process as a critical state requiring immediate termination/notification.

9. Workspace-scoped execution permissions

Where possible, Codex should support an execution mode where write/delete permissions are restricted to:

active workspace
approved temporary/build directories

rather than inheriting unrestricted write access from the user's normal Windows account.

Suggested regression test

In a disposable Windows VM/test volume:

X:\
├── workspace\
│   └── project\
│       └── build\
│           └── target\
└── MUST_NOT_DELETE\
    └── sentinel.txt

A test should verify that no Codex-generated cleanup command intended for:

X:\workspace\project\build\target

can delete or traverse:

X:\MUST_NOT_DELETE

even when:

  • the target contains reserved/problematic names;
  • the initial cleanup fails;
  • an extended \\?\ path is involved;
  • PowerShell 5.1 is the parent shell;
  • output becomes truncated;
  • the child process remains alive.

Evidence available privately

The reporter has retained:

  • the original Codex session rollout-*.jsonl;
  • NTFS USN Journal extraction covering the incident;
  • screenshots of the Codex terminal/transcript;
  • Git working-tree evidence;
  • IDE Local History showing the pre-incident project state.

These artifacts contain local/project-identifying information and are therefore not attached publicly, but relevant sanitized excerpts can be provided privately to maintainers if required.

Recovery status

The active project was recovered successfully.

Other affected repositories were recoverable from remote Git history.

The project was intentionally paused after the incident pending root-cause analysis and safety hardening.

Requested outcome

Please investigate:

  1. destructive-command generation and quoting on Windows PowerShell;
  2. workspace containment checks for recursive filesystem deletion;
  3. safety behavior when escalating after cleanup failure;
  4. handling of still-running destructive background commands;
  5. stronger runtime-level safeguards that prevent an agent mistake from escaping the active workspace.

The central safety requirement is:

A cleanup operation authorized for a build directory must not be capable of deleting files outside that workspace, even if command quoting or shell parsing is wrong.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the Windows cleanup path that passes a validated PowerShell path through cmd.exe /c to rd, then inspect how child-process completion and background termination are handled. Use the suggested disposable Windows VM test with a MUST_NOT_DELETE sentinel, including reserved names, extended paths, failed cleanup, truncated output, and a still-running child; done means cleanup cannot escape the target and destructive processes are not left running.

Written by the indexing model from the issue text.

Assessment

Tech stack
powershell, rust
Domain
operating-systems, security, tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.