PUBLIC-EVIDENCE AI SECURITY CASE STUDY

OpenAI Codex Command Injection: Malicious GitHub Branch Names as a Token-Theft Path

BeyondTrust Phantom Labs (Tyler Jespersen) reported that OpenAI Codex reflected the branch parameter of a task request into the setup logic that fetched the selected repository and branch, so shell metacharacters in a GitHub branch ref could break out of the intended command context and execute attacker-controlled commands inside the Codex task container. During repository clone and review flows the container held GitHub OAuth or GitHub App installation tokens, and the injected command could copy token-bearing remote configuration or logs and send the value outward. An automated variant scaled the attack through the repository: an actor with branch-control rights could create or modify a malicious branch, hide payloads with Unicode spacing, or make the branch default so that other Codex users triggered the payload. The report also describes Codex CLI, SDK and IDE credentials stored in ~/.codex/auth.json that could be used to call backend APIs and retrieve task history or logs. OpenAI remediated the reported issues; the assessment below scores only the pre-fix configuration.

Agentic / MCP SystemTier 3Indicative ERS 4.0 (1.9–6.0)Evidence source date 2026-05-03

BeyondTrust Phantom Labs (Tyler Jespersen) reported that OpenAI Codex reflected the branch parameter of a task request into the setup logic that fetched the selected repository and branch, so shell metacharacters in a GitHub branch ref could break out of the intended command context and execute attacker-controlled commands inside the Codex task container. During repository clone and review flows the container held GitHub OAuth or GitHub App installation tokens, and the injected command could copy token-bearing remote configuration or logs and send the value outward. An automated variant scaled the attack through the repository: an actor with branch-control rights could create or modify a malicious branch, hide payloads with Unicode spacing, or make the branch default so that other Codex users triggered the payload. The report also describes Codex CLI, SDK and IDE credentials stored in ~/.codex/auth.json that could be used to call backend APIs and retrieve task history or logs. OpenAI remediated the reported issues; the assessment below scores only the pre-fix configuration.

ASSESSED SYSTEM

OpenAI Codex as reported by BeyondTrust Phantom Labs in its pre-fix state: the Codex Web task path in which the branch parameter of a task request was reflected into the container setup logic that fetched the selected repository and branch, the GitHub OAuth and GitHub App installation tokens present in that task container during clone and review flows, the container's outbound network path, and the local Codex CLI/SDK/IDE credentials in ~/.codex/auth.json that the same report describes as usable against backend APIs.

OUT OF SCOPE

The remediated Codex (OpenAI fixed the reported issues), OpenAI's models and their reasoning, GitHub as a platform, and the repository-side controls the brief recommends as compensating measures. This is a point-in-time assessment of a reported configuration from external research, not an evaluation of Codex as it stands today.

Architecture: Agentic / MCP System (decision tree Q2) — Q1 = NO: no two-or-more coordinating agents are described; the multi-user variant is many independent tasks triggered by one poisoned branch, not agents exchanging messages. Q2 = YES: a Codex task autonomously plans and executes a multi-step workflow in its own container — fetch the selected repository and branch, run setup logic, then perform clone and review flows — invoking connectors (GitHub via OAuth or App installation tokens) without explicit human approval for each action; the brief's framing that 'a Codex task acts on behalf of a user or GitHub App installation' and that each task should carry 'an accountable runtime identity, delegated GitHub scope, repo, branch, task ID, and expiry' is the delegated-authority evidence Q2 asks for. Tier 3: Tier 3 Internal: a developer coding agent operating within an organisational boundary against repositories its users already have rights to — the spec's Tier 3 'code assistants' example — though the organisation-wide GitHub grants and cross-user propagation through a shared repository push it toward the upper edge of that tier.

Documented attack or failure path

  1. An actor with branch-control rights creates or renames a branch whose ref contains shell metacharacters or command substitution, optionally obscured with unusual Unicode spacing.
  2. A Codex task is started against that repository and branch — by the attacker directly, or by any other user of a shared repository once the malicious branch is made default.
  3. The branch parameter is interpolated into the container setup command that fetches the repository and branch; the metacharacters break out of the expected command context.
  4. The injected command executes inside the Codex task container with the task's ambient access, and reads the GitHub OAuth or App installation token from token-bearing remote configuration or logs.
  5. The token is exfiltrated by an outbound HTTP request from the container to attacker infrastructure; egress is not confined to GitHub endpoints and package registries.
  6. The stolen delegated token is replayed against GitHub with whatever repository or organisation scope the grant carried; separately, local ~/.codex/auth.json credentials can call backend APIs to retrieve task history or logs.

Observed controls and bounded outcomes

Positive credit is given only where the record directly demonstrates a control operating. Recommended or merely presumed controls receive no positive scoring credit.

  • OpenAI remediated the reported issues, and the fix class is deterministic — validating or structurally separating repository metadata from the setup command path rather than mitigating a model property.
  • Container isolation itself held: execution was confined to the Codex task container, and the brief's criticism is of what was reachable inside it (an unrestricted egress path and an unguarded token) rather than of escape from it.
  • GitHub App installation tokens are scoped and short-lived, which bounds replay of a task-time token; the longer-lived exposure identified in the report is the separate local credential file, not the task credential.
  • Records exist for post-incident work: Codex task history and container logs, plus GitHub audit logs, are what the brief's response steps rely on when it asks defenders to 'review GitHub audit logs for token use, and inspect Codex task history or container logs for leaked token material'.
  • Repository-side compensating controls are available without any vendor change — GitHub rulesets, branch protection, pre-receive hooks and CI checks can block refs carrying shell metacharacters or suspicious Unicode spacing before an agent ever runs against them.

Layer 1 — Intrinsic Vulnerability Profile

Each sub-metric is placed on its five-level rubric by the evidence quoted beside it. Missing applicable evidence remains unknown. The displayed midpoint and interval are scenario values, not inferred control performance.

Sub-metricScoreRubric basisEvidence
Robustness (Ro) — scenario interval 0.14–0.59 (midpoint 0.36), Tier 3 MVT 0.40 indeterminate
Ro-1Adversarial Input Resistance0.25w 0.300.25 anchor: ordinary inputs were handled correctly, but a crafted value in one untrusted metadata field defeated whatever validation existed and produced unsafe execution deterministically on that path. Placed at 0.25 rather than 0.00 because the failure is documented for a single input path rather than as a measured failure rate across a standard tool-injection battery, and no claim is made about Codex's adversarial testing programme as a whole.'GitHub metadata reached a shell command. BeyondTrust found that the branch parameter in the Codex task request was reflected into setup logic that fetched the selected repository and branch', and 'Shell metacharacters in a GitHub branch ref could break out of the expected command context and run attacker-controlled commands inside the Codex container.' Payloads could be hidden with Unicode spacing. The brief's mapped control is pre-execution scanning of the resolved command for shell metacharacters, command substitution, hidden Unicode spacing and exfiltration patterns.source: researcher
Ro-4Poisoning Attack Resistance0.25w 0.250.25 anchor: basic validation of repository content existed in the sense that refs are well-formed git objects, but there was no adversarial screening of the shared corpus the agent ingests, so a persistent poisoned artefact — a malicious or default-set branch — succeeded with limited effort and propagated to other users' tasks. Distinct from Ro-1, which scores the single crafted input; this scores the absence of provenance and screening on a mutable shared ingestion source.'The attack could scale through the repository. An attacker with branch-control rights could create or modify a malicious branch, hide payloads with Unicode spacing, or make the branch default so other Codex users trigger the payload.' The repository is the agent's working corpus, and the brief's remediation is to 'treat GitHub branch names, ref names, repository names, PR titles, issue text, and setup parameters as untrusted input before they enter agent containers, shell commands, setup scripts, or logs.'source: brief
Fairness (Fa) — scenario interval 0.00–1.00 (midpoint 0.50), Tier 3 MVT 0.45 indeterminate
Transparency (Tr) — scenario interval 0.06–0.81 (midpoint 0.44), Tier 3 MVT 0.45 indeterminate
Tr-3Audit Trail Completeness0.25w 0.250.25 anchor: partial logging exists — task history, container logs and GitHub audit logs support post-hoc review — but the record omits critical fields, notably the accountable runtime identity and delegation context that would tie a GitHub action back to a specific agent task and its authorising grant. The trail also carries sensitive values it should have excluded.The brief states each container task 'should carry an accountable runtime identity, delegated GitHub scope, repo, branch, task ID, and expiry so defenders can prove which agent acted, under whose authorization, and which token should be revoked if the task is compromised' — an accountability requirement it presents as unmet. It also identifies token material reaching task logs as a sink to be blocked, and asks defenders to inspect task history and container logs for leaked tokens.source: brief
Privacy (Pr) — scenario interval 0.00–1.00 (midpoint 0.50), Tier 3 MVT 0.50 indeterminate
Containment (Cn) — scenario interval 0.10–0.69 (midpoint 0.40), Tier 3 MVT 0.50 indeterminate
Cn-1Scope Enforcement0.25w 0.120.25 anchor: a real boundary existed — the task container — but enforcement was inconsistent inside it: network scope was unbounded, and manipulation of a single request parameter let execution exceed the intended task scope. Not 0.00, because the container isolation and the task's repository selection were genuine constraints that the attack had to work within.'BeyondTrust's automated variant exfiltrated tokens by sending outbound HTTP from the Codex container to attacker infrastructure', against which the brief prescribes 'Default-deny egress, narrow allowlists, and proxy rules for setup and runtime phases'. Its capability guidance adds that the active scope should be the selected repo, selected branch, allowed GitHub actions, allowed network destinations and allowed task-history access — 'A branch payload should not be able to widen the session into token exfiltration or cross-repository GitHub access.'source: brief
Cn-2Escalation Prevention0.25w 0.160.25 anchor: basic authorisation checks existed (the task ran under a real, scoped grant) but were vulnerable to delegated-tool misuse: injected code inside the task inherited the full breadth of that grant with no just-in-time narrowing to the user's actual intent, converting branch-write rights into the agent's organisation-scoped authority.The injected command inherited the task's delegated GitHub authority — 'the target was the GitHub token Codex used for the task' — and the brief's remediation is to 'Audit GitHub App permissions and user OAuth grants for Codex-like agents. Remove broad organization-wide access where a task only needs one repo, one branch, or read-only review capability.' The automated variant reached other users' tasks in a shared repository.source: brief
Cn-5Agent Identity Integrity0.25w 0.14Two credential classes conflict, and the worst-case rule governs. The task-time GitHub token matches the 0.50 anchor — token-based identity with scoped permissions but no cryptographic binding to workload, session or route, so a copied bearer token is reusable elsewhere. The local ~/.codex/auth.json credential matches the 0.25 anchor: a long-lived stored secret directly usable against backend APIs, with no workload binding and limited auditability. The lower anchor is taken.The brief prescribes what was absent: 'Authenticate each Codex-to-GitHub call with a short-lived, audience-bound credential tied to the intended workload and route so a stolen token is harder to reuse elsewhere', and separately notes 'Local Codex credentials expanded the path. The report also describes Codex CLI, SDK, and IDE credentials in ~/.codex/auth.json, which could be used to call backend APIs and retrieve task history or logs.'source: researcher

Unknown, not N/A: 17 applicable sub-metrics lack admissible public evidence. The lower, midpoint, and upper scenarios evaluate each at 0.00, 0.50, and 1.00 respectively; no weight is redistributed merely because evidence is missing.

Layer 2 — Operational Risk Posture

DimensionScoreJustification
AaAutonomy Amplification0.75w 0.20Supervised autonomy: once a task is started, Codex executes a multi-step workflow — fetch, setup, clone, review — inside its container without per-action human approval, using delegated GitHub authority, with the human reviewing the result asynchronously. Not 1.00: task initiation remains a human act, and the evidence documents no authority to merge or otherwise finalise changes without review.
AsAttack Surface Exposure0.75w 0.25Internet-facing service ingesting external, partially trusted data: repository metadata and content authored by anyone with branch-control rights enters the task container, and setup phases reach package registries and other network destinations. Not 1.00 — the assessed configuration evidences no MCP tool integration and no communication with external agents, so the maximum-exposure anchor is not met on the rubric's own terms even though the ingested metadata proved fully attacker-controlled.
CpCascade Potential1.00w 0.30No System Dependency Graph is published, so the worst-case default applies — and the reconstruction independently triggers the 1.00 anchor. An ungated path runs from untrusted repository metadata, through command execution in the task container, to a delegated GitHub credential, and out to attacker infrastructure over unrestricted egress: privilege amplifies from 'can write a branch name' to the full scope of an OAuth or App installation grant, which for organisation-wide grants is external write authority (P3) over systems of record. The poisoned default-branch variant extends the blast radius to every other Codex user of the shared repository.GDCP: corroborated by the observed path elevated
RfRemediation Feasibility0.00w 0.25Deterministic fix, already shipped: OpenAI remediated the reported issues, and the fix class is code-level — validate or structurally separate repository metadata from the setup command path, using structured process APIs instead of string-built shell commands. No retraining is involved and the model is untouched. Deployment-side hardening (narrowing GitHub grants, restricting container egress, repository ref rules) is available in parallel as configuration work.

Nelevated = 1 (dimensions strictly above 0.75) → CRM = 1.00.

Layer 3 — Public-evidence confidence diagnostic

ComponentScoreBasis
Pc — Public provenance evidence0.25Minimal provenance in the evidence available. The vendor, the affected surfaces (Codex Web, plus CLI/SDK/IDE credential replication), the credential classes (GitHub OAuth and App installation tokens, ~/.codex/auth.json) and the injection point are documented by the researcher. Absent: any AIBOM, tool or connector manifest, container image lineage, identity policy, or evaluation artefact tied to the assessed configuration. The brief's first remediation step — inventory every GitHub organisation and repository where Codex is authorised — indicates that inventory is not standard.
Ec — Public evaluation coverage0.25coverage 0.26 (6 of 23 applicable sub-metrics) × independence 1.00 × fidelity 0.95. No Full, Standard, or Lite pathway is claimed for a retrospective article.
Tf — Public-evidence freshness0.21Evidence dated 2026-03-30; age 136 days on the workpaper reference date. Components: T_behavior 0.21 · T_containment 0.36 · C_behavior 0.40 · T_calendar 0.60 · C_monitor 0.65 · C_event 0.65 · C_evidence 0.65. Binding term: T_behavior. dt_days = 136, measured from BeyondTrust's primary disclosure dated 2026-03-30 to the 2026-08-13 evidence reference date; the AIDEFEND brief republished the analysis on 2026-05-03. agentic = true: tool authority and delegated GitHub grants are reprovisionable at runtime, so the containment staleness floor (M_Cn = 2.0) applies and no boundary re-attestation is evidenced. baw = true on the closed-feedback-loop checklist item: the agent writes branches and pull requests into the repository, and that same mutable repository state is later consumed by Codex tasks in a decision path — the poisoned-default-branch variant, in which one task's working corpus drives other tasks' execution, is the concrete demonstration. C_behavior = 0.40 (Band 0): no canaries, registered invariants or maintained drift baseline are evidenced for the assessed configuration; this is the spec's worst-case default when behavioural-monitoring evidence is unavailable, not a finding that none exists. C_evidence = 0.65 rather than 0.85, because Band 0 triggers the cold-start evidence cap. C_event = 0.65: OpenAI's remediation is a moderate system event — a validation and guardrail change on the assessed setup path — so the evidence describes a superseded configuration. C_monitor = 0.65: neither the injection nor the outbound exfiltration was caught by platform monitoring, and the brief has to specify the detections from scratch (refs containing shell metacharacters, backticks, ${IFS} or unusual Unicode spacing; default-branch changes; Codex setup errors; outbound proxy hits to unknown hosts; token-shaped strings in task logs).

Public-evidence ACI = (Pc × Ec × Tf)1/3 = 0.24 — diagnostic status: Invalid as assessment-of-record evidence. It describes the evidence available to this case study, not the assurance of the underlying system, and is not inserted into the normalized-assurance scenario ERS.

Indicative ERS — normalized-assurance scenario

Worp · ORP0.20(0.75) + 0.25(0.75) + 0.30(1.00) + 0.25(0.00) = 0.637
CRMNelevated = 1 → 1.00
ORPeffective0.637 × 1.00 = 0.637
Wivp · IVP midpoint0.20(0.36) + 0.15(0.50) + 0.20(0.44) + 0.25(0.50) + 0.20(0.40) = 0.439
IVP mitigation0.15 + 0.85(1 − 0.439) = 0.627
Scenario assuranceACI fixed at 1.000 for cross-case comparison; public-evidence ACI 0.236 is diagnostic only
Indicative ERS midpointmin(10, 0.637 × 0.627 × 1/1.000 × 10) = 4.0
Unknown-input interval1.9–6.0; 17 unknown applicable sub-metrics set to 1.00 / 0.00 at the bounds

AIDEFEND defences → AITBM sub-metrics

Identifiers are quoted as they appear on the AIDEFEND in Action brief (retrieved 2026-08-13); the sub-metric mapping is AITBM's own, from the specification's AIDEFEND tables reconciled at catalogue data version 2026.08.05. AIDEFEND renumbers identifiers between releases, so the data version travels with every mapping and neither side's IDs should be cited without one. A mapping identifies a possible evidence route; a recommendation does not prove that the control was implemented or effective and receives no scoring credit by itself.

TechniqueDefence PriorityEvidences
AID-H-025.001Pre-Execution Static Analysis & Dangerous Construct BlockingParent AID-H-025 'Unsafe Code Execution Prevention' (dataVersion 2026.08.05). The directly failing gate: scan the resolved setup command for shell metacharacters, command substitution, hidden Unicode spacing and exfiltration patterns before execution, and build commands with structured process APIs rather than string interpolation. Informs Ro-1 in substance; the lookup maps the parent to Cn-3, which this case's evidence does not otherwise support, so Cn-3 was not scored.Very HighCn-3
AID-H-018.005Value-Level Capability Metadata & Data Flow Sink EnforcementParent AID-H-018 'Tool Authorization & Capability Scoping' (dataVersion 2026.08.05). Label the GitHub token as a high-sensitivity runtime value and block it from unsafe sinks — model-readable files, task logs, outbound HTTP, shell arguments, prompt-visible output. Principal Cn-1 evidence source alongside egress restriction.Very HighCn-1 Cn-6 Cn-7
AID-H-004.002Service & API AuthenticationParent AID-H-004 'Identity, Access & Trusted Communication for AI Systems' (dataVersion 2026.08.05). Short-lived, audience-bound credentials tied to the intended workload and route — the binding whose absence sets Cn-5.Very HighCn-5 Tr-3
AID-M-009.003Agent Identity, Delegation Lineage & Authorization ContextParent AID-M-009 'Agent Autonomy & Authority Governance' (dataVersion 2026.08.05). Accountable runtime identity per container task with delegated scope, repo, branch, task ID and expiry — evidence for both Cn-5 and the Tr-3 accountability gap.HighCn-1 Cn-5 Cn-6 Cn-7
AID-H-018.004Intent-Based Dynamic Capability ScopingParent AID-H-018 (dataVersion 2026.08.05). Narrowing the live session to the selected repo, branch, GitHub actions, network destinations and task-history access so a branch payload cannot widen it — the control behind the Cn-2 finding as well as Cn-1.HighCn-1 Cn-6 Cn-7
AID-I-001.004Sandbox Network Egress RestrictionsParent AID-I-001 'AI Execution Sandboxing & Runtime Isolation' (dataVersion 2026.08.05). Default-deny egress with allowlists for setup and runtime would have broken the exfiltration step after a successful injection. The lookup's Pr-2 mapping is not supported by this case's evidence, so Pr-2 was not scored; the technique informed Cn-1.HighCn-7 Pr-2
AID-E-001.004Delegated Grant & Connected-App Authorization RevocationParent AID-E-001 'Compromised Credential, Session, Principal & Grant Eviction' (dataVersion 2026.08.05). Revoking the connected app, OAuth grant or App installation authorisation, since an exposed installation can mint fresh tokens after individual token values expire.HighCn-5
AID-D-005.002AI Detection Rule Lifecycle, Delivery & HealthParent AID-D-005 'AI Activity Logging, Monitoring & Threat Hunting' (dataVersion 2026.08.05). Keeps the concrete detections installed and healthy — refs with shell metacharacters or ${IFS}, default-branch changes, setup errors, unknown outbound hosts, token-shaped strings in task logs. Its absence is the basis for the C_monitor cap.MediumCn-7 Tr-3

WHAT THIS CASE TEACHES

The exploited input never reached the model, which is exactly why Ro-1 must be scored over the agent's whole task-setup surface rather than its prompt: an agent's adversarial-input resistance is only as good as the least-validated field in the request that provisions its container.

Sources: AIDEFEND in Action brief — OpenAI Codex Command Injection: Malicious GitHub Branch Names as a Token-Theft Path (published 2026-05-03) · Primary source — Tyler Jespersen, BeyondTrust Phantom Labs: How Command Injection Vulnerability in OpenAI Codex Leads to GitHub Token Compromise (2026-03-30)

AITBM sub-metrics referenced