One Issue Away

Opening an issue is the most harmless thing you can do on GitHub. You do not need to be a contributor. You do not need to fork anything or get a review. You type some text and press a button.

In a repository that runs an AI agent on its issues, that is now enough to take the agent over.

We went looking for how often that happens. We collected 800 public repositories whose GitHub Actions run an AI coding agent, and read every workflow our scanner rated as serious. In 16 of them, a stranger who opens an issue or a pull request can make the agent do what they say. In six of those, the agent can also reach the repository's secrets.

Three settings that are each reasonable

None of these repositories did anything that looks careless. Each of them combined three settings, and each setting on its own has a good reason behind it.

Anyone can start it. The workflow runs on issues or issue_comment, or on a pull request from a fork. That is the whole point of a triage bot: it answers the people who show up.

The safety gate is off. Anthropic's claude-code-action refuses, by default, to act for users who do not have write access to the repository. One input turns that off:

allowed_non_write_users: "*"

The action's own documentation describes it plainly: a list of users to allow without write permissions, or * to allow all users. Teams set it because a triage bot that ignores outside contributors is not much of a triage bot.

The agent has real tools. A write token, and tools like Bash, git or Write, so it can label, fix and push.

Put the three together and it looks like this:

on:
  issues:
    types: [opened]

permissions:
  contents: write
  issues: write

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          allowed_non_write_users: "*"
          claude_args: "--allowedTools Bash,Edit,Write"
          prompt: "Read the new issue, label it, and fix it if you can."

That is an illustration, not a copy of any repository. Not all 16 use this exact action, but every one of them combines the same three things. An attacker opens an issue that says, in the middle of an ordinary bug report, to ignore the task and do something else. The agent reads the issue because reading issues is its job. Depending on what it was given, the attacker can post as the bot, push code to the repository, or run commands on the runner with the secrets that live there.

Why it does not look dangerous

To an agent, an attacker's instruction and a real one are the same thing: text in its context that tells it what to do. There is no marker that separates the two, and a better prompt does not create one. The agent is doing exactly what it was built to do, for whoever wrote the words it read.

The workflow does not look dangerous either. It looks like a helpful bot, because it is one. Nothing in the diff that added it would catch a reviewer's eye. The gate is one line of YAML, and it is often not even written by the team: among the medium findings, one duplicate-issue detector appears in 17 repositories, with the gate-off line carried along in every copy.

Where the risk lives

In this set, the large projects were fine. Every finding sits below 10,000 stars:

starsrepositoriesverified findings
above 50,000680
10,000 to 50,000860
1,000 to 10,000934
below 1,00055312

That fits what you would expect. Big projects have someone whose job is to read a workflow like the one above and ask what an outsider could do with it. The risk is in the middle: real projects with real users, running an agent on their issues, and nobody on the team whose job is to think like an attacker.

A note on the numbers. The 800 are not a random sample. We deliberately went looking for repositories that run agents in CI, and a large share came from searching for the exact settings described above. So 16 out of 800 is not a rate for GitHub as a whole. It is how many of these setups turned out to be exploitable once we read them.

The ones halfway there

Below the 16 there is a longer list of repositories rated medium: 245 of them. In 114, the gate is already off. The agent answers anyone. What keeps those repositories out of the first group is only which tools the agent was given. Today it can label an issue or post a comment. The day someone gives it Bash so it can also try a fix, it joins the 16.

That is the part worth taking seriously. The dangerous configuration is not a rare mistake. It is a reasonable setup, one convenient change away from a serious one.

What to check in your own repository

If you run an agent from GitHub Actions, five questions settle whether an outsider can drive it:

  1. Is the gate on? Search your workflows for allowed_non_write_users. If it is *, anyone can trigger the agent.
  2. What does the agent read? If untrusted code from a fork is checked out into the workspace, or the issue text goes straight into the prompt, the attacker's words reach the agent.
  3. Can the agent's shell see your secrets? A token or cloud credential in the environment is what turns a hijacked bot into a stolen key.
  4. Is the token scoped? A narrow, short-lived token limits the damage. A static personal access token does not.
  5. Are the tools scoped? Bash(gh issue label:*) lets the agent do one thing. Bare Bash lets it do anything.

You can check all five in one pass. This reads a public repository with no install and no account:

npx node9-ai scan-repo <owner>/<repo>

It reads the committed workflows and agent configuration, runs nothing, and tells you which of these settings line up.

No affected repository is named in this post. Each of the 16 was confirmed by reading the workflow by hand, not only by the scanner. If one of them is yours, the fix is usually the first question on the list: turn the gate back on, or scope what the agent can do before you let everyone talk to it.

Share
XRedditHacker NewsLinkedIn

Related posts

Security · MCP

The MCP Rug Pull - When the Tool You Trusted Yesterday Becomes Malicious Today

The MCP rug pull is a supply-chain attack that traditional scanners can't catch. The package hash doesn't change. The tool surface does - between sessions, while the package is at rest. Two defenses worth shipping today: tool definition pinning and per-call authorization at the execution boundary.

Security · AI

Structure or Text: Two Ways to Read a Command, and Why We Needed Both

We wrote a post called Why Regex Is Not Enough. It was right about what a parser buys you and incomplete about what it costs. Here is the distinction we should have drawn the first time.

Security · AI

What Can a Hijacked AI Agent Actually Reach on Your Machine?

A compromised coding agent doesn't need a zero-day - it inherits everything your shell can reach, and its malicious reads look exactly like its helpful ones. Runnable checks to see your own blast radius, why exfil hides in traffic you approved, and how to read your exposure score in ten seconds.