The Incident
On 2026-03-30, BeyondTrust Phantom Labs publicly disclosed a command injection vulnerability in OpenAI Codex that let attackers steal a victim’s GitHub User Access Token from the per-task Codex container by encoding shell commands into a malicious repository branch name. When a Codex user ran a prompt against an attacker-controlled repository, the task-creation flow concatenated the attacker-supplied branch name into a git clone command without quoting or sanitization, executing the attacker’s shell inside a container that already held the user’s plaintext OAuth token. Affected surfaces included the ChatGPT website, the Codex CLI, the Codex SDK, and the Codex IDE Extension. BeyondTrust reported the issue to OpenAI via BugCrowd in December 2025; OpenAI shipped an initial mitigation within a week and completed full remediation of the branch-name shell escape by January 2026. No CVE ID was assigned — OpenAI handled the fix through BugCrowd rather than the CVE process, and Codex’s server-side code is closed-source, so no public commit or pull request documents the change.
The payload had to fit through GitHub’s branch-naming rules, which forbid spaces. The attacker substituted ${IFS} to bypass the space restriction and embedded the malicious tail of the branch name behind 94 ideographic spaces (Unicode U+3000), followed by || true. The Codex UI rendered the U+3000 characters as benign whitespace, so a victim glancing at the branch name saw only the harmless-looking prefix; the destructive shell ran in the container regardless, and the in-memory GitHub User Access Token was reachable from that shell. The disclosure landed alongside a separate OpenAI patch for a ChatGPT data-exfiltration flaw, which several outlets reported as a coordinated 2026-03-30 release. MITRE ATT&CK coverage: T1059.004 (Command and Scripting Interpreter: Unix Shell), T1027 (Obfuscated Files or Information — the U+3000 visual hiding), T1552 (Unsecured Credentials — the in-container token), and T1550.001 (Use Alternate Authentication Material: Application Access Token — the post-theft reuse path).
The Authority Path That Failed
The identity carrying execution authority at the moment of failure was the per-task Codex container that OpenAI provisioned to service a single user prompt. That container held the user’s GitHub OAuth token in plaintext. Its intended exercised scope was narrow — clone the target repository, run a code-modification task the user explicitly approved. What it actually exercised was arbitrary shell, against attacker-controlled input, inside the same trust boundary as the credential it was holding for the user.
The trust anchor that failed first was input handling at the boundary between the Codex task-creation HTTP request and the container’s shell. A branch name — constrained only by GitHub’s lax naming grammar, and partially obscured to the user by Unicode whitespace — was treated as data when it was in fact a command. The pre-incident question is not “did Codex sanitize this string?” It is “which agent runtimes hold long-lived VCS credentials in the same trust boundary as untrusted prompt-derived input?” That gap — held scope (a broadly-authorized OAuth token) versus exercised scope (a single user-approved task) — was visible from the runtime’s identity surface long before any branch name was crafted.
SecurityV0 Perspective
This is nhi_compromise. The exploitable asset is a non-human identity — a GitHub User Access Token co-located with a shell context reachable from attacker-controllable input — and the durable harm is the stolen token, not the moment of shell injection. Command injection is the delivery mechanism; the authority failure is that an agent runtime mounted a long-lived VCS credential into a sandbox that processed adversarial inputs at the same privilege.
The evidence pack SecurityV0 would produce for this finding: a per-runtime inventory of every long-lived OAuth token, PAT, or service-account credential the agent’s execution sandbox can reach, with token scope, last-rotation timestamp, and issuing identity; a map of every untrusted input vector that can reach that sandbox (prompts, commit messages, branch and tag names, issue titles, file contents, HTTP headers); and the delta between them — every credential whose lifetime outlives the task that requires it, every input boundary that lacks an enforcement gate. Pre-incident, that pack answers “could a hostile branch name reach a shell that holds my token?” Post-incident, the same pack scopes the blast radius: which user tokens were resident in any Codex task container during the vulnerable window, what repositories they could read or write, and which of those repositories saw activity the human user did not initiate.
What To Do
- Treat agent runtimes that hold VCS credentials as authorization choke points, not sandboxes. Any container — hosted or self-managed — that materializes a GitHub OAuth token, PAT, or installation token in plaintext while also accepting prompt-derived input is one vulnerability away from the BeyondTrust scenario. Inventory those runtimes and require an explicit attestation of which untrusted inputs reach the same trust boundary as the credential.
- Replace long-lived agent tokens with OIDC-minted, task-scoped credentials. Substitute long-lived OAuth tokens in Codex-style sandboxes with short-lived, repository-scoped tokens issued per task — GitHub App installation tokens with
Contents:readonly, or workload-identity-federated tokens that expire when the task ends. The token Codex held was capable of far more thangit clone. - Sanitize git-reference inputs before they reach a shell. Branch names, tag names, and ref strings have permissive grammars; any code path concatenating them into a shell or libgit invocation must defensively quote and use hard argv separation (
git clone --branch <ref> -- <repo>). Reject refs containing${,$(, backticks, or non-printable Unicode. - Surface non-printable Unicode in prompt and ref UI. The 94 U+3000 ideographic-space technique worked because the Codex interface rendered the obfuscation as benign whitespace. Agent and code-review UIs should normalize and visibly mark non-ASCII-whitespace runs in repository refs, file paths, and prompt parameters; the BeyondTrust write-up shows how readily this defeats human review.
- Audit GitHub OAuth grants for every AI coding agent in your org. Every user who installed Codex or a similar coding assistant authorized an OAuth scope set; revisit those grants with the specific question “if this agent’s runtime were compromised tomorrow, what could be done with my token?” Downscope to specific repositories where possible, and rotate tokens that were resident in a Codex task between December 2025 and the January 2026 remediation.
Sources
- BeyondTrust Phantom Labs — OpenAI Codex Command Injection Vulnerability
- SecurityWeek — Critical Vulnerability in OpenAI Codex Allowed GitHub Token Compromise
- SiliconANGLE — OpenAI Codex Vulnerability Enabled GitHub Token Theft via Command Injection
- The Hacker News — OpenAI Patches ChatGPT Data Exfiltration Flaw and Codex GitHub Token Vulnerability
- CSO Online — OpenAI patches twin leaks as Codex slips and ChatGPT spills
- TechRadar — Unicode characters being weaponized to hide malicious commands from human users
- Bank Info Security — Codex Bug Let Repo Files Execute Hidden Commands
- Hackread — OpenAI Codex Vulnerability Allowed Attackers to Steal GitHub Tokens
- MITRE ATT&CK: T1059.004, T1027, T1552, T1550.001