The Incident
On 2026-06-04, GMO Flatt Security researcher RyotaK disclosed a chain of flaws in Anthropic’s official anthropics/claude-code-action — CVSS v4.0 7.8, fixed in claude-code-action v1.0.94 — that let an unauthenticated external attacker take over any public repository running the action by opening a single GitHub issue. The core defect was a bypass in the checkWritePermissions function: it treated any actor whose login ended in [bot] as authorized, so an attacker who registered a public GitHub App could file an issue under their bot identity and pass the permission gate. Chained with indirect prompt injection inside the issue body, the attacker coerced Claude to read the runner’s ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL, echo them back into a comment, mint an OIDC token, and exchange it with Anthropic’s backend for a Claude GitHub App installation token with contents:write. Because anthropics/claude-code-action itself ran the vulnerable workflow on its own repository, a successful exploit could have pushed malicious commits into the action and propagated to every downstream consumer pinned to it.
RyotaK reported the core bypass in January 2026; Anthropic patched within four days, hardened further through the spring, shipped the consolidated fixes in v1.0.94, and paid a $3,800 + $1,000 bounty. Microsoft Threat Intelligence separately disclosed an adjacent finding on 2026-06-05: the Claude Code Read tool would read /proc/self/environ to lift ANTHROPIC_API_KEY. That issue was reported via HackerOne on 2026-04-29 and mitigated in Claude Code 2.1.128 on 2026-05-05. MITRE ATT&CK coverage: T1199 Trusted Relationship, T1552.001 Credentials In Files, T1059 Command and Scripting Interpreter, T1195.002 Compromise Software Supply Chain.
The Authority Path That Failed
Two identities co-execute inside claude-code-action: the GitHub Actions runner — carrying GITHUB_TOKEN, the OIDC request credentials, and any workflow secrets — and the Claude agent, carrying its tool set (Bash, Read, the gh wrapper) plus whatever allowed_tools the operator granted. The intended trust boundary was that only actors with repository write permission could trigger the agent on untrusted input. The boundary failed because checkWritePermissions was a string-shape heuristic: any *[bot] login was treated as authoritative without verifying installed-app permissions, and GitHub Apps can open issues from any installation token on a public repository.
The scope Claude held — Bash, Read, OIDC token request, and write-back to issues — far exceeded the scope its operator intended, which was “triage this issue.” The trust anchor that failed first was the bot-suffix check; Anthropic’s own example workflows compounded it by shipping allowed_non_write_users: "*", which removed the gate entirely for many adopters. The gap was statically visible: an agent invoked on issues: opened with id-token: write, write-capable tools, and no human-approval gate is an Agents Rule of Two violation that an authority-aware control plane would have surfaced before any issue was ever filed.
SecurityV0 Perspective
This is scope_drift (ASI03). A Claude agent deployed to triage was coerced through untrusted issue content into exfiltrating runner secrets and minting an installation token. Held authority and exercised authority diverged, and the gap closed catastrophically: the operator asked the agent to read a GitHub comment; the attacker made the agent mint a write-capable installation token for the repository. Cline’s February 2026 post-mortem makes this concrete — the same attack class, against a different Claude triage workflow, ended in an unauthorized [email protected] npm publish and roughly 4,000 downloads over an eight-hour window before takedown.
The evidence pack SecurityV0 would have produced before exploitation lists every repository whose workflow simultaneously grants an AI agent untrusted input (issues: opened, pull_request_target), secret access, and external-write tooling — then ranks each by realized blast radius (OIDC subject, app installation scope, downstream consumer count). The pre-exfiltration question the pack answers is “which agent identities can be persuaded by an external actor into actions their operator never sanctioned?” The post-exfiltration forensic question, queried at the alert: “which OIDC subjects were active during the suspect window, which installation tokens were minted, and which downstream commits trace back to a minted-during-injection identity?”
What To Do
- Bind permission checks to GitHub’s permission API, not actor-string shape. Replace any
actor.endsWith("[bot]")heuristic withoctokit.repos.getCollaboratorPermissionLevel({owner, repo, username})and gate strictly onadminorwrite. Reject bot identities whose installation lacks write on the target repository. - Drop
allowed_non_write_users: "*"and any equivalent wildcard. The official Anthropic example workflows shipped this; upgrade toclaude-code-actionv1.0.94 and remove the wildcard. If non-write users must trigger the agent, gate them behind an explicit allowlist and require a maintainer assignment step. - Apply the Agents Rule of Two: pick at most two of {untrusted input, secrets, external-write tools}. A workflow on
issues: openedwithid-token: writeandcontents: writeholds all three. Split the trigger surface — untrusted-input agents read only; secret-touching agents run on trusted triggers like push to a protected branch or manual dispatch with approval. - Scrub the runner environment before the agent process starts. v1.0.94 adds environment scrubbing for child processes; adopt it. Drop
ACTIONS_ID_TOKEN_REQUEST_TOKEN,ACTIONS_ID_TOKEN_REQUEST_URL, and any non-whitelisted secret from the agent’s environment, and use the v1.0.94 customghwrapper that validates arguments and blocks known exfiltration URL patterns. - Inventory which AI-agent identities can mint installation tokens, and reconcile them against operator intent. For each repository running Claude Code Action — or Gemini CLI Action, or Copilot Agent — produce a standing permission ledger: which
GITHUB_TOKENscopes, which OIDC subjects, which app installations, and which downstream consumers pin the action. A one-time audit catches the worst offenders; a standing inventory catches drift.
Sources
- GMO Flatt Security Research — Poisoning Claude Code: One GitHub Issue to Break the Supply Chain
- Microsoft Security Blog — Securing CI/CD in an agentic world: Claude Code Github action case
- The Hacker News — Claude Code GitHub Action Flaw Let One Malicious Issue Hijack Repositories
- Cline post-mortem — Unauthorized Cline CLI npm publish (2026-02-17)
- anthropics/claude-code-action issue #351 — checkWritePermissions / getCollaboratorPermissionLevel
- MITRE ATT&CK: T1199, T1552.001, T1059, T1195.002