Feb 19, 2026·5 min read·95 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')
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.