Summary
According to GMO Flatt Security researcher RyotaK, the trigger check in the Claude Code GitHub Action unconditionally trusted any actor whose name ends in [bot]. Anyone can register a GitHub App and use its token to create issues on any public repository, so an attacker’s issue passes as “a bot trigger,” and an agent with write access can execute the instructions planted in its body. The researcher demonstrated this on his own test repositories, and the fix was available before publication. Unless, before an agent runs with privilege, the authority of whoever triggered it and the origin of the input it reads are checked against separately managed records rather than a name or the look of the text, a trigger and instructions anyone can create become privileged operations as they are.
A pre-execution check means checking, before an agent runs with privilege, the authority of whoever triggered it and the origin of its input, and keeping a record. Detection means a researcher finding and reporting the bypass. Dates are those of the report, the fix, and publication, not of any use of the path.
were shown able to drive the agent's privileged run
What got through
- What got through
- Triggering the agent with an issue created by the attacker’s own GitHub App. The trigger check (
checkWritePermissions) took the[bot]name suffix as grounds for authority, and agent mode lacked the human confirmation that tag mode had (RyotaK). Then Claude could execute, as “recovery,” instructions in an issue body disguised as an error message (RyotaK). - What reached the receiving side
- In general, an agent running in CI holds the secrets passed to the workflow and write access to the repository. In the researcher’s report, having secrets in environment variables written back into the issue, stealing the credential used for the OIDC token exchange, and replaying the exchange reaches write access to the target’s code, issues, and workflows. Aimed at the claude-code-action repository itself, it could poison the Action that downstream consumers pull in.
- Secondary paths
- Anthropic’s example workflow included
allowed_non_write_users: "*"(anyone can trigger; flagged as a risk in the docs too), and Claude posted task summaries to the publicly visible run-summary field, so repositories that copied it inherited the same hole. An attacker without trigger rights could also slip content in as “trusted input” by editing a trusted user’s issue after it triggered but before Claude read it (RyotaK). - Not disclosed
- Any use of this path against a real-world target. The researcher’s write-up says the demonstration was limited to his own test repositories.
Pre-execution check
Whatever the route, the condition for telling them apart is that, before an agent runs with privilege, whether whoever triggered it holds authority for that operation, and where the input it reads came from and whether it has changed since the trigger, are checked separately from a name or the look of the text.
Unless, before an agent runs with privilege, the authority of whoever triggered it and the origin of the input it reads are checked against separately managed records rather than a name or the look of the text, a trigger and instructions anyone can create become privileged operations as they are.
- Who approves
- The repository administrator, who decides which people and which installed Apps may trigger the agent. An actor’s name suffix or the wording of an issue body is not used as approval.
- Where it is checked
- Immediately before the agent moves to execution holding secrets and write access. Whether the triggering party is on the allowed list is checked against permission records, not a name. The input it reads is checked against the version at trigger time, and a trigger or input that cannot be checked is held until it is.
- What is recorded
- Who triggered the agent, under what authority, and what it executed (or held) on which version of the input. Kept separately from the agent, in a form that can be shown later.
Discovery of the flaw and publication after the fix worked, and Anthropic fixed it within four days of the report. CI logs let what was executed be traced afterwards. What was missing is the layer before that, which checks the trigger’s authority and the input’s origin. It has the same shape as Brief 037, where an agent auto-executed a repo-bundled config, Brief 048, where an AI read instructions invisible to humans, and Brief 029, where a stolen token was not scoped to the action: the agent’s privileged operation is not tied to a check of its trigger and input.
What Lemma does
Lemma builds the pre-execution check in immediately before the agent moves to execution holding secrets and write access. It does not detect malicious issues or prompt injection; before execution, it checks the authority of whoever triggered the agent and the version of the input it reads, separately from a name or the look of the text.
Industries and operations to watch
- IndustryDevelopers & agent operations
- Development and operations teams that embed AI agents in CI/CD and have them triage issues, apply labels, and review PRs.
- IndustryAI
- Organizations operating platforms where agents holding real tokens and tools run on input arriving from outside.
- OperationAgent runs triggered by issues and PRs
- Work in public repositories where issues or PRs created by outside people or Apps trigger the agent. The trigger check and the input read lead straight to operations with write access.
Current controls vs Lemma
The core route in this case is the first column: a trigger by a party without authority. The second column is the post-trigger edit the researcher reported as a secondary path; the third compares the case where instructions are contained in input a legitimate trigger supplied.
| Control | Trigger by a party without authority (claiming [bot]) | Input slipped in after a legitimate trigger (editing the issue after it triggered) | Instructions in input supplied by a legitimate trigger |
|---|---|---|---|
Trigger check by the [bot] name suffix (before the fix) | Not effective | Not relevant | Not relevant |
| Auditing workflows for who or what can trigger (Anthropic’s recommendation) | Partial | Not relevant | Not relevant |
| Limiting secrets and exfiltration-capable tools and permissions when handling unverified input (Anthropic’s recommendation) | Partial | Partial | Partial |
| Lemma (pre-execution check) | Effective | Effective | Not effective |
The name-suffix check could be satisfied by the name of a GitHub App anyone can register (RyotaK). Auditing workflows finds and removes settings that let anyone trigger, but a hole in the check itself remains. Limiting secrets and tools narrows what can be reached in every column, but does not stop the trigger or the execution of instructions. Lemma checks the triggering party against the list the administrator allowed and the permission records, and checks the input against its version at trigger time, so a trigger by name alone, or input replaced after the trigger, is held before execution. On the other hand, if instructions are contained in the input a legitimate trigger supplied, the check matches and it passes. That column is covered in combination with limiting secrets and tools.
Note: Lemma’s check works only when it is built into the step that triggers the agent, and the list of allowed triggers, the permission records, and the record of input versions are managed separately from the input the agent reads. If the key of an App or person the administrator allowed is stolen, or malicious instructions are executed within the allowed scope, it can pass. Lemma does not change claude-code-action’s implementation and does not judge whether the content of the input is benign. The table compares what each control checks; it does not show whether this incident would have been stopped. Lemma does not detect or prevent intrusions.
Three things to confirm for organizations that trigger AI agents in CI/CD from issues and PRs
- Is the claude-code-action you use at or above the version where the fixes converged (v1.0.94)?
- Have you left in place settings copied from example workflows that let anyone trigger (such as
allowed_non_write_users: "*"), or output to publicly visible fields? - In workflows that handle unverified input, do you pass the agent only the secrets it needs (the Anthropic API key and
GITHUB_TOKEN)?
Facts and timeline
- Target
- Anthropic’s Claude Code GitHub Action (claude-code-action), which embeds Claude in CI/CD to triage issues, apply labels, review PRs, and run slash commands. By default it has read/write access to the repository’s code, issues, PRs, discussions, and workflow files.
- Severity and fix
- 7.8 under CVSS 4.0. The fixes converge in claude-code-action v1.0.94. Anthropic paid a bug bounty.
- Reporter
- GMO Flatt Security researcher RyotaK, who reported the core bypass to Anthropic in January 2026.
- The researcher’s report (trigger)
- The trigger check (
checkWritePermissions) unconditionally trusted any actor whose name ends in[bot](on the assumption that a GitHub App is trusted, installed by an admin). Anyone can register a GitHub App, install it on their own repository, and use its installation token to create issues or PRs on any public repository. Tag mode had an additional human-confirmation check; agent mode did not. - The researcher’s report (input and reach)
- Instructions are planted in an issue body disguised as an error message, leading Claude to execute them as “recovery.” Having secrets in environment variables written back into the issue, stealing the credential used for the OIDC token exchange, and replaying the exchange yields an installation token with write access.
- Secondary paths (the researcher’s report)
- Repositories that copied the example workflow’s
allowed_non_write_users: "*"and output to the public run-summary field inherited the same hole. Editing an issue after it triggered, before Claude read it, could slip content in as trusted input.
Glossary
GitHub App and installation token — A GitHub App is an integration installed on repositories. The installation token issued per installation can create issues and PRs. Its actor name ends in `[bot]`.
OIDC token — A signed token stating "I am this workflow running in this repository." Claude Code exchanges it with Anthropic's backend for an installation token of the Claude GitHub App, which has write access.
Indirect prompt injection — Planting instructions in documents or data an AI reads (here, an issue body) so that the AI executes them as instructions.
Timeline
- 2026-01
- RyotaK reports the core bypass to Anthropic. Anthropic fixes it within four days.
- Spring 2026
- Additional hardening continues; the fixes converge in claude-code-action v1.0.94.
- 2026-06-04
- The details are published (GMO Flatt Security’s research post, The Hacker News, and others).
This was handled as a coordinated disclosure, published after a fix was available. Facts about the technique follow GMO Flatt Security’s research post and The Hacker News’s coverage; the fix follows Anthropic’s fix commit. There is no public trace of “this exact path” poisoning Anthropic’s Action being used against a real-world target, and RyotaK says he demonstrated it only on his own test repositories. With the same shape of setup (AI issue triage, broad permissions, prompt injection), a February 2026 case in which an npm publish token was stolen via Cline’s claude-code-action workflow and a malicious version published has been reported as a separate route. RyotaK says he reported roughly 50 techniques for circumventing the permission system. This Brief does not include reproduction steps. What has not been disclosed does not mean there were no controls.
After disclosure
- Anthropic: Fixed the core within four days of the report and hardened through the spring; the fixes converge in claude-code-action v1.0.94. It advises users to audit workflows where non-write users or bots can trigger Claude, to pass no secrets beyond the Anthropic API key and
GITHUB_TOKENwhen handling unverified input, and to remove tools and permissions usable for exfiltration. - Example configurations: Copying example settings as they are, such as
allowed_non_write_users: "*"or output to publicly visible fields, was pointed out as something that can widen the hole.
Sources
- GMO Flatt Security (primary, researcher): RyotaK, “Poisoning Claude Code: One GitHub Issue to Break the Supply Chain” — https://flatt.tech/research/posts/poisoning-claude-code-one-github-issue-to-break-the-supply-chain/
- The Hacker News: “Claude Code GitHub Action Flaw Let One Malicious Issue Hijack Repositories” (2026-06-04) — https://thehackernews.com/2026/06/claude-code-github-action-flaw-let-one.html
- Anthropic (primary, fix commit): claude-code-action fix commit (converging in v1.0.94) — https://github.com/anthropics/claude-code-action/commit/1bbc9e7ff7d48e1299f7fa9698273d248e0cafea
References: “The last layer left for cyber defense in the age of AI”