Skip to content

Prompt Injection in AI Code Review: How to Protect Your Repo

How PromptPwnd, Clinejection and Comment and Control showed PR and issue text exposing CI secrets, and the workflow controls that limit the damage.

Published 9 min readBy the Warpway team

Prompt injection in AI code review happens when text anyone can write, such as a pull request title, description, comment or issue, reaches a model that also holds secrets or write access. The model then follows that text instead of reviewing it. The 2025–26 incidents below all leaked credentials this way. To protect a repository, keep secrets and write tokens away from any job that reads untrusted text, avoid pull_request_target for agent workflows, give the agent read-only tools, treat PR text as data, and let deterministic checks, not a model, decide what merges.

How the attack works

Aikido Security named the PromptPwnd class and describes the chain as "untrusted user input → injected into prompts → AI agent executes privileged tools → secrets leaked or workflows manipulated." Three conditions have to line up:

  1. Attacker-controlled text reaches the prompt. This includes PR titles and bodies, issue titles and bodies, comments and commit messages, often interpolated straight into the prompt with expressions like ${{ github.event.pull_request.body }}.
  2. The agent's runtime holds something worth stealing. An AI provider API key, a GITHUB_TOKEN with write scopes, cloud credentials or publishing tokens.
  3. The agent has tools that act. A shell, file edits, or the ability to post to issues and pull requests. Posting doubles as the exfiltration channel.

Routing the text through an environment variable does not help. Aikido notes that environment variables stop shell command injection, but the model still receives the attacker's text. Each control later in this guide removes one of these three conditions.

Three incidents from 2025–26

IncidentEntry pointWhat the agent heldHow it leaked
PromptPwnd (Dec 2025)Issue title and bodyGemini API key, Google Cloud token, GITHUB_TOKEN with issue and PR writeThe agent ran gh issue edit and wrote keys into the issue body
Clinejection (Feb 2026)Issue titleShell, write and edit tools; Anthropic API keyIt poisoned the Actions cache that the nightly release workflow loaded, which exposed that workflow's publishing tokens
Comment and Control (Apr 2026)PR title, issue title and comments, hidden HTML commentsAPI keys, GITHUB_TOKEN, other runner secretsPosted as review "findings" (Claude Code) or an issue comment (Gemini); routed through GitHub's own API (Copilot)

PromptPwnd

Aikido's December 2025 disclosure centered on the gemini-cli repository, which triaged issues with google-github-actions/run-gemini-cli. The workflow passed the issue title and body into the prompt, and the agent had a shell tool limited to commands such as gh issue edit. A hidden instruction in an issue told the model to rewrite the issue body with the values of $GEMINI_API_KEY and $GITHUB_TOKEN, and the model did it. Aikido tested on a private fork with test credentials, and Google patched the workflow within four days. Aikido says at least five Fortune 500 companies were affected by the same pattern. It also flags settings that widen exposure: allowed_non_write_users: "*" for Claude Code Actions, allow-users: "*" for Codex, and enable-github-mcp: true for GitHub AI Inference.

Clinejection

Adnan Khan's February 9, 2026 write-up shows why least privilege on one job is not enough. Cline's triage workflow ran anthropics/claude-code-action@v1 on every new issue, with allowed_non_write_users: "*" and tools including Bash, Write and Edit. The issue title went straight into the prompt. The triage job's GITHUB_TOKEN was restricted, and its only direct secret was the Anthropic API key. But every workflow in a repository can read and write the Actions cache. Code running in the triage job could fill the cache past GitHub's 10 GB limit, which evicts older entries, and then write poisoned entries under the keys the nightly release workflow restored. That release workflow held VSCE_PAT, OVSX_PAT and NPM_RELEASE_TOKEN. Khan reported the issue on January 1, 2026, and the fix landed within an hour of public disclosure. According to the timeline in his post, an unauthorized Cline CLI 2.3.0 was published on February 17, after the npm token was not properly revoked during rotation.

Comment and Control

On April 15, 2026, Aonan Guan, Zhengyu Liu and Gavin Zhong disclosed one injection pattern that worked against three agents. According to the Cloud Security Alliance's research note:

  • Claude Code Security Review inserted the PR title into its prompt. A crafted title led it to run commands and post ANTHROPIC_API_KEY and GITHUB_TOKEN as "findings" in a PR review comment.
  • Gemini CLI Action was steered by an issue title plus comments containing a fabricated "trusted content section," and it published its API key in an issue comment.
  • GitHub Copilot Agent read a payload hidden in an HTML comment, which is invisible in rendered Markdown. The note says the attack got past environment-variable filtering, secret scanning (by encoding the values) and the network firewall (by routing through GitHub's API).

SecurityWeek reports that the vendors' fixes closed specific paths: Anthropic blocked the ps tool, and Google added guardrail prompts. GitHub classified the issue as a known architectural limitation. Guan's framing explains why fixing prompts is not enough: "the prompt injection here is not a bug; it is context that the agent is designed to process." A reviewer has to read the PR. What you can control is what it can reach and do after reading it.

Five controls for your repository

1. Least-privilege tokens, and no secrets next to untrusted text

The CSA's May 2026 note points out that without an explicit permissions block, GITHUB_TOKEN gets the repository's default permissions, often read-write. Set read-only at the workflow level and raise scopes per job. Remove API keys the agent does not need, scope the rest to minimum permissions, and use short-lived keys where your provider supports them. The CSA also recommends separating the agent from credentials, so write tokens and keys are used only in downstream jobs after review.

Clinejection adds one more boundary: caches. Khan recommends that release and other privileged workflows not restore caches, and that nightly releases use their own credentials and package namespace.

2. Care with pull_request_target

GitHub Security Lab's guidance on "pwn requests" explains the trigger. pull_request_target runs in the context of the base repository, with that repository's secrets and a read/write token, even when the pull request comes from a fork. Checking out and building the PR head under this trigger is the classic mistake. An AI agent adds risk even without a checkout, because the PR's title and body become the payload. The CSA calls the trigger "categorically more dangerous" once a model interprets the workflow's input at runtime.

Use pull_request instead, which by default gives fork PRs no secrets and no write access. If a result must be written back, use GitHub Security Lab's split: an unprivileged pull_request workflow saves its output as an artifact, and a separate workflow_run workflow that holds the token acts on it, treating the artifact as untrusted. Label gates are only a stopgap, because GitHub Security Lab notes they are prone to a race condition.

The trade-off is real. An Actions-based reviewer that needs a model API key cannot review fork PRs under pull_request without exposing that key. Either restrict it to branches in your own repository, or require maintainer approval for first-time contributors, as the CSA suggests. Same-repository PRs are not automatically safe either: if the agent reads comments, anyone who can comment can supply its input.

yaml
name: ai-review
on:
  pull_request:              # not pull_request_target
permissions:
  contents: read             # workflow default: read-only
jobs:
  review:
    if: github.event.pull_request.head.repo.full_name == github.repository
    runs-on: ubuntu-latest
    permissions:
      contents: read         # no pull-requests: write in the job that reads PR text
    steps:
      - uses: actions/checkout@<full-commit-sha>
        with:
          persist-credentials: false
      - name: Review with read-only tools, no shell, no GitHub writes
        env:
          MODEL_API_KEY: ${{ secrets.REVIEW_MODEL_KEY }}   # scoped key, short-lived if possible
        run: ./scripts/ai-review --out findings.json
      - uses: actions/upload-artifact@<full-commit-sha>
        with:
          name: findings
          path: findings.json
# A separate workflow_run workflow scans findings.json for secrets,
# then posts it with pull-requests: write. The agent never holds that token.

3. Give the agent only the tools it needs

For triage, Khan recommends no Bash, Write or Edit: only file reads and the GitHub CLI calls the task needs, set with the narrowest --allowedTools. Aikido recommends avoiding tools that write to issues or pull requests, since posting is how PromptPwnd and two of the three Comment and Control cases got secrets out. Do not set allowed_non_write_users: "*" or allow-users: "*" on workflows that outsiders can trigger. Pin third-party actions to commit SHAs, but remember the CSA's caveat that pinning does not fix the injection itself.

4. Treat PR text as data

Never interpolate ${{ github.event.* }} text into a prompt where it reads like instructions. Put it in a clearly delimited block that the prompt identifies as data. Strip or encode HTML comment blocks before the model sees them, which is the CSA's recommendation after the Copilot case. Treat model output as untrusted too: scan anything the agent will post for secrets, and never execute its output without validation. Delimiting lowers the odds of a takeover but does not remove them, which is why it belongs alongside controls 1 to 3.

5. Let deterministic gates decide the merge

If a model's verdict can approve or merge code, an injected "this looks safe" is enough to get a change in. Make the merge decision come from code: required status checks whose conclusions are computed from stored results, required human approvals, and a ruleset that names the app allowed to report each check. A hijacked reviewer can then write a wrong comment, but it cannot merge anything. Blocking merges on AI review findings covers the GitHub setup. Read review policy from the base branch too, so a PR cannot edit the rules that judge it.

Audit your workflows

  1. Find event text that reaches a prompt, plus triggers and settings that widen who can start a run:
bash
grep -rnE 'github\.event\.(issue|pull_request|comment|review)\.(title|body)|head_commit\.message' .github/workflows/
grep -rnE 'pull_request_target|issue_comment|allowed_non_write_users|allow-users|enable-github-mcp' .github/workflows/
  1. For each AI workflow, list its secrets, its permissions and its allowed tools. An agent that can run a shell or write to GitHub while reading outsider text matches the PromptPwnd pattern.
  2. Check whether any release or other privileged workflow restores a cache that a low-privilege workflow can write.
  3. Confirm that no AI verdict alone satisfies a required check or approval.
  4. Rotate keys that untrusted PRs could have reached, and confirm the old ones are revoked.

How Warpway handles untrusted PR text

Warpway reviews pull requests as a GitHub App, not as an agent in your Actions runners. Its security docs describe prompt-injection defenses that "do not depend on a model noticing an attack":

  • No secrets, and no write tools for the model. Lens tools are read-only and Contents access is read-only. The app's write permissions (Pull requests and Checks) are used by Warpway's code to post the summary comment and check, request reviewers and, if enabled, approve. The GitHub permissions page states that the app cannot push, create branches, merge, change branch protection, or read repository or organization secrets, and it does not request Actions access. Installation tokens last one hour and are kept in memory only. Model API keys are held in Warpway's encrypted environment configuration.
  • Delimited input. PR text, comments, repository files, tickets and Slack messages reach the model inside marked blocks. Any block delimiter inside the content is neutralized first, and every prompt states that those blocks cannot change instructions, tools, output format or access.
  • Fixed tool scope. Lens tools read one repository at one commit. They take no repository or organization parameters from the model, and their allowlist comes from your configuration. No tool runs shell commands.
  • Deterministic decisions. Code computes policy satisfaction, the Warpway / Review conclusion and auto-approval eligibility from stored results. Warpway never approves because a model reported high confidence. Policy is read from the base branch, so a PR cannot relax its own review.
  • Attempts become findings. The Security lens is instructed to report text that tries to steer the review, such as a request to approve the change or reveal the prompts, as a finding.
  • No command text in runtime verification. If you let Warpway run tests in your Actions through runtime verification, you install a separate Warpway Runtime app that has only Actions: write and repository metadata access. Warpway dispatches only profiles you approved and sends four values but no commands. It runs the base branch's copy of the workflow, and it does not verify pull requests from forks.

Limits to keep in mind: Warpway works with GitHub only, and it does nothing about AI workflows you already run in .github/workflows. The model still reads PR text, delimited as untrusted data. These controls limit what injected text can do, but they don't make a model immune to being misled. That is why the merge decision stays with deterministic code and, through merge gating, with your GitHub branch rules.

Frequently asked questions

What should I do if an AI workflow may have leaked a token?

Rotate every key that untrusted pull requests or issues could have reached, as the Cloud Security Alliance recommends, and confirm the old credential is actually revoked. In the Clinejection timeline, an npm token that was not properly revoked during rotation was later used to publish an unauthorized release. Search the workflow's Actions logs and the comments it posted for secrets or encoded strings, and purge caches that privileged workflows restore if the compromised job could write to the cache.

Does pinning GitHub Actions to a commit SHA stop prompt injection?

No. Pinning protects you from a tag being moved to different code, but the Cloud Security Alliance notes it does not fix the injection flaw itself. A pinned agent still follows instructions hidden in the text it reads. Pin anyway, and pair it with read-only permissions and narrow tools.

Can an AI code reviewer detect prompt injection in a pull request?

It can flag attempts, and some reviewers are told to. Warpway's Security lens, for example, reports text that tries to steer the review as a finding. Treat detection as a backstop, because the Comment and Control payloads were built to get past filters and guardrail prompts. Design the pipeline so that a reviewer that misses an attempt still cannot leak a secret or merge the change.

Is a GitHub App reviewer safer than an AI agent running in GitHub Actions?

They expose different things. An agent in Actions runs inside your runner with whatever secrets and token that job receives, which is what the 2025 and 2026 attacks exposed. A GitHub App acts with the permissions its installation grants, so read its permission list and check whether it can write contents, merge or reach secrets. In either case, the model that reads PR text should not be what decides a merge.

Sources

  1. PromptPwnd: Prompt Injection Vulnerabilities in GitHub Actions Using AI Agents (Aikido Security)
  2. Clinejection — Compromising Cline's Production Releases just by Prompting an Issue Triager (Adnan Khan)
  3. Comment and Control: GitHub AI Agents as Credential Exfiltrators (Cloud Security Alliance, April 2026)
  4. Prompt Injection in AI-Powered GitHub Actions (Cloud Security Alliance, May 2026)
  5. Claude Code, Gemini CLI, GitHub Copilot Agents Vulnerable to Prompt Injection via Comments (SecurityWeek)
  6. Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests (GitHub Security Lab)