Codex security · Windows Windows
Safer Codex on Windows.
Limit what Codex can read, change, and send — then verify the setup and recover from mistakes.
Community project · Not affiliated with OpenAI
- workspace write
- workspace sandbox reads
- explicit network policy
- outside-workspace writes
- StrictProfile credentials
- unrestricted network
Approval is not a security boundary.
Faced with a destructive command, most people’s first instinct is: “I’ll write clear instructions and approve everything important myself.” But approval only protects you if you can actually read every command — and on Windows, with its quoting rules, encodings, registry entries, and endless parameters, that is far harder than it sounds.
Commands get longer, approvals repeat dozens of times a day, and sooner or later you skim, misread, or only see the first half. Reviewer agents misjudge too. When approval is the only line of defense, one wrong click hands over full authority.
Read the whole script once before looking at the answer below. There is no malicious line in sight — but it deletes a folder you never meant to touch.
Set-Location "C:\Users\you\projects\webapp"
$ErrorActionPreference = "SilentlyContinue"
if (-not (Test-Path "C:\Users\you\projects\webapp\node_modules")) {
npm ci --no-audit --no-fund --loglevel=error
}
$config = Get-Content "C:\Users\you\projects\webapp\tools\build-config.json" -Raw -ErrorAction SilentlyContinue | ConvertFrom-Json
$base = $config.outputDirectory
npm run build -- --outDir "$base" --minify
Copy-Item -Path "$base\*" -Destination "C:\Users\you\projects\webapp\release\latest" -Recurse -Force -Confirm:$false
Remove-Item -Path "$base\data" -Recurse -Force -Confirm:$false
git add -A; git commit -m "sync build output"; git push origin main A routine build-and-release script.
By the time you reach the final lines, line 7 looks completely innocent: $base takes its value from the config. But the config read failed quietly — $base is $null. Not one line in this script was written to cause the accident.
$config = Get-Content "C:\Users\you\projects\webapp\tools\build-config.json" -Raw -ErrorAction SilentlyContinue | ConvertFrom-Json$base = $config.outputDirectoryRemove-Item -Path "$base\data" -Recurse -Force -Confirm:$false PowerShell resolves paths starting with \ from the root of the current drive — here, C:. The config file is missing, so the read fails quietly and $base is $null: "$base\data" becomes \data, and "$base\*" becomes \*. Copy-Item first copies whatever it can read from C:\* into release\latest; Remove-Item targets C:\data. Whether the deletion actually lands depends on C:\data existing and on your permissions. Danger did not come from a dangerous line — two locally reasonable choices combined into a path you never meant.
Risk one · Agent accidents — no malice required
Completing the task correctly is not the same as completing it safely. Nothing in these commands is evil; the outcome is simply wrong.
git fetch origin main --quiet git reset --hard origin/main git clean -fdx -e ".env.local" -e "node_modules"
An ordinary request: bring the repo back to a clean state of remote main.
It never checks whether the working tree holds your only copy of anything. reset --hard discards tracked changes; clean -fdx wipes even ignored files. The task is correct — the completion is unsafe.
Risk two · More permission than the task needs
These are not reasoning accidents — they are what granted permissions allow: code you cannot audit, and one-time approvals that keep executing later.
powershell.exe -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQA9ACcAUwBpAGwAZQBuAHQAbAB5AEMAbwBuAHQAaQBuAHUAZQAnADsAIABHAGUAdAAtAEMAaABpAGwAZABJAHQAZQBtACAAIgAkAGUAbgB2ADoAVQBTAEUAUgBQAFIATwBGAEkATABFAFwALgBhAHcAcwAiACwAIgAkAGUAbgB2ADoAVQBTAEUAUgBQAFIATwBGAEkATABFAFwALgBzAHMAaAAiACAALQBSAGUAYwB1AHIAcwBlACAALQBGAG8AcgBjAGUAIAAtAEUAcgByAG8AcgBBAGMAdABpAG8AbgAgAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAIAB8ACAARgBvAHIARQBhAGMAaAAtAE8AYgBqAGUAYwB0ACAAewAgAEMAbwBwAHkALQBJAHQAZQBtACAAJABfAC4ARgB1AGwAbABOAGEAbQBlACAAIgBDADoAXABVAHMAZQByAHMAXAB5AG8AdQBcAHAAcgBvAGoAZQBjAHQAcwBcAHcAZQBiAGEAcABwAFwALgBzAGMAYQBuAC0AbwB1AHQAcAB1AHQAIgAgAC0ARgBvAHIAYwBlACAAfQA=
$ErrorActionPreference = 'SilentlyContinue'Get-ChildItem "$env:USERPROFILE\.aws", "$env:USERPROFILE\.ssh" -Recurse -Force |ForEach-Object { Copy-Item $_.FullName "C:\Users\you\projects\webapp\.scan-output" -Force } A common workaround for Windows quoting problems — or a way to hide what actually runs.
Prompt injection and malicious repo instructions look exactly like this under Full Access: Hidden, NonInteractive, ExecutionPolicy Bypass, and a payload no one can audit.
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "WebAppUpdater" -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Users\you\AppData\Local\Temp\upd.ps1" -PropertyType String -Force | Out-Null
Register an updater that starts at login.
The Run entry points at a mutable file: upd.ps1. You reviewed version A today; a replaced version B runs at your next login. One approval becomes a standing execution path that outlives this review.
A user running Full Access discovered that their relay service had injected a script into the execution flow, disguised as “environment monitoring”. They only spotted it because the executed code was visible in the chain of thought — SSH keys and API keys were one step away from being bundled out of the machine.
The script looked harmless, so approval was never the question. With the Custom or StrictProfile read boundary active, disguised code could not have read SSH keys or API keys outside the project.
Every new command is another exam that must be passed perfectly, and a single failure hands over full authority. Codex Safe Setup flips this: approval becomes an optional workflow inside the boundary, and the boundary itself becomes the thing that cannot be crossed.
What it limits
What it limits
Three capability boundaries, with an explicit choice between dynamic UI control and a pinned strict profile.
Files
Codex shouldn’t own your whole filesystem.
DynamicUi keeps runtime switching free of sticky denies. StrictProfile pins persistent root and credential denies.
DynamicUi installs two positive-only runtime profiles. Workspace credential files remain readable; use StrictProfile for persistent explicit denies.
- Workspace write — Writes allowed only under registered workspace roots.
- Workspace sandbox reads — DynamicUi follows the workspace sandbox read scope; StrictProfile narrows reads with explicit rules.
- Filesystem root — Writes are blocked by DynamicUi outside the workspace and explicitly bounded by StrictProfile; Full Access permits them.
- Common credentials — Explicitly denied only by StrictProfile. DynamicUi cannot use sticky deny-globs inside a writable workspace.
Network
Command networking is a separate boundary.
Approving commands is not the same as deciding what can leave your machine. Egress is an explicit, independent choice.
A domain table without an active proxy is not an enforced allowlist.
- Off — Default. Commands cannot reach the network.
- Allowlist — Only explicitly named public domains pass through the command proxy.
- Unrestricted — High risk. Direct command egress, installed only after a separate acknowledgement.
Recovery
Safety includes being able to undo.
Containment prevents mistakes; recovery survives them. Every managed file is backed up, and the optional checkpoint bridge snapshots work without touching your branch.
Checkpoints do not capture ignored or refused files. Restore with a separate worktree: git worktree add <new-empty-directory> <commit>.
- Backup before write — Every file the installer touches is backed up first, with an exact rollback command.
- Git checkpoints — Optional hidden refs under refs/codex-safe/checkpoints/*. Branch, real index, and working tree stay untouched.
- Sensitive untracked files — Refused from checkpoints: .env, private keys, .npmrc, cloud credential files.
- Automatic destructive recovery — Never runs reset --hard, clean, branch replacement, or in-place checkout.
- Replaced Git executable — The bridge refuses to run if the pinned Git SHA-256 changes.
Before & after
Autonomy and containment are not opposites.
A good boundary lets the agent work freely inside it — you don’t become the gatekeeper.
Full Access
Every read, write, and send starts allowed.- agent
- Workspace
- Home directory
- Credentials
- Whole filesystem
- Network
Bounded autonomy
Writes and command egress stay bounded; the selected UI route controls the read boundary.- agent
- Workspace writes
- Zero-deny Custom profile
- Explicit network policy
- Out-of-bound writes and command egress → denied
With the recommended BoundedAutonomy mode, there are no approval prompts inside the boundary — limits do the work approvals were doing.
Approval and command networking are separate decisions. The reviewer choice does not change whichever DynamicUi or StrictProfile filesystem route is active.
Verification
Installed is not verified.
Installing a config is not the same as proving it holds. Verification reports what was actually checked — and what it could not check.
Start one fresh task after a machine-configuration change. Same-task UI permission changes must then apply on the next message without restarting.
- writes outside the workspace
- reads outside the workspace
- workspace secret files
- protected metadata (.git, .codex, .agents)
- deletion recovery (checkpoints)
- command network egress
- rollback and backups
- external surfaces — reported, never implied
A synthetic file placed outside the workspace is used to probe the boundary before any claim is made.
Install
Install Codex Safe Setup
Two commands, one prompt — then the skill audits, explains the tradeoffs, and writes configuration only after you confirm.
PS> codex plugin marketplace add QianQIUlp/codex-safe-setup --ref main
codex plugin add codex-safe-setup@codex-safe-setup Start a new Codex task or CLI session, then ask:
Use $codex-safe-setup to audit my current permissions and install the recommended profile.
Requirements DynamicUi and StrictProfile require Codex CLI 0.138.0 or newer · PowerShell 7 recommended on Windows
Version 0.2.1 removes the retired Windows selector compatibility layer from 0.2.0 and ships a cleanup script for legacy autostart remnants. The GitHub marketplace follows main, whose catalog pins the latest release.
Each release also ships an install-ready ZIP with a .sha256 file. Verify the archive in PowerShell with Get-FileHash -Algorithm SHA256 <archive>.
- 01 Read-only assessment — nothing changes yet.
- 02 Boundaries and tradeoffs explained, not hidden.
- 03 Separate consent for prerequisites (PowerShell 7, Codex CLI).
- 04 Plan-only preview of the exact configuration.
- 05 Applied only after your explicit confirmation.
- 06 Static and execpolicy checks, then a fresh task for real Desktop end-to-end probes.
- 07 Backups recorded — exact rollback stays available.
The boundary
Know the boundary.
A trustworthy security tool states what it does not control. These surfaces use separate control surfaces — each is reported as NOT CONTROLLED, never implied as protected.
- Web Search
- Browser
- Computer Use
- Apps & connectors
- Other plugins
- MCP servers
- Cloud tasks
- Source-control remotes
- CI credentials
- Credentials exposed before installation
- Host malware
- Operating-system compromise
Each appears as NOT CONTROLLED in the verification report.
- Revoke or rotate it immediately.
- Inspect the provider’s usage, sessions, and billing.
- Remove copies from files, logs, shell history, and repository history.
- Timing alone is not proof of causation.
Open source
Built in the open.
Community-built and Apache-2.0 licensed. Source, reproducible builds, and private security reporting on GitHub.
- CI runs isolated integration tests and package validation on Windows.
- Releases are built from validated tags and ship with SHA-256 checksums.
- Each release passed the official Skill and Plugin validators.
- Private vulnerability reporting through GitHub Security Advisories.