You run a vulnerability scanner in your CI/CD pipeline. You trust it. That's the whole point of a security tool.
On March 19, 2026, that trust became the attack vector. The vulnerability scanner was the vulnerability.
Aqua Security's Trivy, a scanner with 32,000 GitHub stars and millions of CI/CD runs per month, was compromised by an autonomous AI agent called hackerbot-claw. Five days later, the compromise had cascaded through five ecosystems (GitHub Actions, Docker Hub, npm, Open VSX, and PyPI), reaching LiteLLM, the Python AI proxy that routes API keys for companies like NASA, NVIDIA, Netflix, and Stripe. Roughly 500,000 exfiltration attempts in roughly three hours before PyPI quarantined both versions.
The Misconfiguration
Trivy had a GitHub Actions workflow called "API Diff Check." It used pull_request_target as its trigger.
If you don't work with GitHub Actions daily, here's why that matters. When someone opens a pull request from a fork, pull_request_target runs the workflow with the permissions of the base repository, not the fork. GitHub designed it this way so maintainers could do things like label PRs or post comments on contributions from external forks.
The security model assumes the workflow code itself is trusted, because it comes from the base branch. That's fine. The problem is what happens next.
Trivy's workflow checked out the fork's code (github.event.pull_request.head.ref) and ran it. And the workflow had access to a Personal Access Token (PAT) stored as a repository secret. Not the default GITHUB_TOKEN, which is scoped to the current repo with limited permissions. A PAT, tied to the aqua-bot service account, with broad write access across multiple Aqua Security repositories.
So the workflow said: when a PR arrives from anyone on the internet, check out their code and run it with our credentials. GitHub's own Security Lab documented this exact anti-pattern in 2021. They called it a "pwn request." Five years later, it was sitting in the workflow directory of one of the most popular security tools in the open source ecosystem.
The Exploit
On February 27, 2026, a threat actor using the GitHub account MegaGame10418 exploited this exact misconfiguration. They opened a pull request. The pull_request_target workflow fired immediately. No human review. No approval gate. The fork's code ran inside the CI runner with access to the PAT.
The PAT was exfiltrated before any maintainer could have possibly reviewed the PR diff. Around the same time, an autonomous AI agent called hackerbot-claw (self-described as "powered by claude-opus-4-5") was systematically scanning public repositories for the same class of misconfiguration, hitting repos from Microsoft, DataDog, and CNCF.
With the stolen PAT, the attacker deleted all 178 Trivy releases, wiped the repository's stars, and published a malicious VS Code extension under Aqua's trusted publisher identity.
Trivy wasn't the only target. hackerbot-claw hit at least seven repositories using different techniques tailored to each repo's workflow configuration. awesome-go (140K stars) lost its GITHUB_TOKEN via a poisoned Go init() function. A Microsoft AI repo was targeted via branch-name injection. A CNCF project (project-akri) had confirmed RCE through comment-triggered workflows. DataDog's IAC scanner was probed. One target (ambient-code/platform) used AI prompt injection against a Claude-based CI workflow, which Claude actually blocked. Five of seven targets achieved remote code execution in CI. Every single exploit used well-documented misconfigurations that have been public knowledge since 2020.
The Twenty Days
Aqua Security disclosed the breach on March 1 and rotated credentials. This is the right response. But the rotation wasn't atomic.
Aqua's VP of open source, Itay Shakury, later acknowledged: "We rotated secrets and tokens, but the process wasn't atomic, and attackers may have been privy to refreshed tokens." During the rotation window, as old credentials were being invalidated and new ones issued, the attacker captured the refreshed tokens before access was fully severed.
For twenty days (February 27 to March 19), the attacker held valid credentials and did nothing visible. No alerts. No anomalous activity. Just quiet, patient access to a security company's infrastructure. Then on March 19 at 17:43 UTC, they struck.
This is the part most post-mortems will understate. The initial exploit was a known misconfiguration. The cascade across five ecosystems was enabled by a credential rotation that looked successful but wasn't. GitGuardian's analysis puts it plainly: "Incomplete cleanup turns one breach into a campaign."
The hard problem isn't detecting the leak. It's proving that every credential reachable from the compromised context has been revoked, that no new credentials were exposed during the rotation itself, and that non-human identities (service accounts, PATs, publish tokens) haven't been silently duplicated. Aqua did the right things. They disclosed fast, they rotated credentials, they published post-mortems. But "rotated credentials" and "severed all access" are not the same thing, and the twenty-day gap between them is where the entire campaign lived.
The Cascade
Using the retained credentials, TeamPCP pushed a malicious Trivy release (v0.69.4), spoofing commits to look like they came from legitimate maintainers (impersonating rauchg and DmitriyLewen). They force-pushed 75 out of 76 trivy-action version tags and 7 setup-trivy tags to point at malicious commits. Any organization referencing these actions by version tag (not pinned to a commit SHA) pulled the malicious code.
The malicious GitHub Actions scraped Runner.Worker process memory for secrets, swept filesystems for SSH keys and cloud credentials, encrypted everything with AES-256 + RSA-4096, and exfiltrated it. Thousands of organizations ran these workflows between March 19 and when the compromise was detected.
Between March 21 and 22, stolen credentials unlocked Checkmarx KICS, Docker Hub (where malicious Trivy images 0.69.5 and 0.69.6 were published), npm (via a worm called CanisterWorm using stolen publish tokens), and Open VSX.
Each breach produced credentials that unlocked the next target. As Wiz's head of threat exposure put it: "We are stuck in a loop."
LiteLLM: The Fifth Domino
LiteLLM used Trivy in its CI/CD pipeline. On March 23, the attacker used a compromised maintainer PAT to push malicious workflows to the BerriAI/litellm repository. The workflow dumped all GitHub secrets via ${{ toJSON(secrets) }}, encrypted them, and uploaded the results as an artifact. The PYPI_PUBLISH token was among the harvested secrets. The next morning, March 24 at 10:39 and 10:52 UTC, versions 1.82.7 and 1.82.8 were uploaded directly to PyPI. Neither had a corresponding GitHub tag or release.
Version 1.82.7 injected malicious code in litellm/proxy/proxy_server.py, executed on module import. Version 1.82.8 added a .pth file. Python auto-executes .pth files on every interpreter startup. You didn't need to import litellm. You didn't need to run it. Just having it installed in your environment meant every Python process on your machine ran the malware.
The payload collected SSH keys, cloud credentials (AWS, GCP, Azure), Kubernetes secrets, .env files, crypto wallets, and database passwords. It encrypted everything and sent it to models.litellm[.]cloud. On Kubernetes hosts, it deployed privileged pods to every node and installed a persistent systemd backdoor (sysmon.service) polling checkmarx[.]zone for additional payloads.
LiteLLM averages 3.4 million downloads per day. It sits in the dependency tree of dspy, MCP plugins, agent frameworks, and countless internal tools. Many of the victims never ran pip install litellm. It was a transitive dependency. They never chose to install it.
The malware was caught because of a bug in its own code. The .pth launcher spawned a child Python process, which triggered the .pth again, creating an exponential fork bomb that crashed machines. FutureSearch security researcher Callum McMahon noticed his machine dying when a Cursor MCP plugin pulled litellm as a transitive dependency via uvx. He investigated and reported it. PyPI quarantined both versions roughly three hours after publication. If the malware had been written more carefully, it could have gone undetected for days or weeks. TeamPCP later claimed 54GB of stolen data via DM to vxunderground. BleepingComputer reports roughly 500,000 exfiltration attempts.
What Would Have Caught This
The original vulnerability was a YAML file in .github/workflows/. A file that defined the "API Diff Check" workflow. The dangerous combination was right there in the configuration: pull_request_target as the trigger, actions/checkout referencing the PR head, and a PAT in the secrets.
This is a known pattern. GitHub Security Lab published the advisory in 2021. It's in every CI/CD security checklist. It's in the training data of every major language model. Point Claude Code or Codex at the .github/workflows/ directory, ask "are any of these workflows vulnerable to pwn request attacks," and you'd have the answer in seconds.
An AI agent compromised Trivy by exploiting a misconfigured workflow. A different AI agent, reviewing the same repository, would have flagged that misconfiguration before any attacker found it. The cost of that review: a few seconds of compute. The cost of not doing it: a cascading supply chain compromise across five ecosystems and 500,000 machines.
The workflow YAML sat in that repository for months. Hundreds of contributors looked at the codebase. Nobody reviewed the CI configuration. Because workflows are plumbing. They get set up once and forgotten. And that's exactly why they're such effective attack surface.
Eight Ways Your Workflows Can Be Exploited
Pwn requests (the Trivy vector) are one class of GitHub Actions vulnerability. There are at least seven others, and hackerbot-claw used different ones against different targets in the same campaign.
Expression injection. When a workflow interpolates untrusted input like ${{ github.event.issue.title }} or ${{ github.head_ref }} directly into a run: block, an attacker can embed shell commands in a branch name, PR title, or issue body. The workflow executes them. This is what hackerbot-claw used against Microsoft's ai-discovery-agent and DataDog's IAC scanner.
Mutable action tags. Referencing actions/checkout@v4 instead of pinning to a full commit SHA. Tags can be force-pushed to point at malicious commits. TeamPCP repointed 75 trivy-action tags this way. Every org referencing those tags by name pulled malicious code.
Comment-triggered command injection. Workflows that fire on issue_comment and parse the comment body for commands like /deploy or /sync-metadata. If the workflow doesn't verify author association, any commenter can trigger privileged actions. This is what hit project-akri (CNCF).
Artifact poisoning. Workflow A produces a build artifact from a fork PR with untrusted code. Workflow B downloads and uses that artifact with elevated permissions. The artifact is tainted but trusted because it came from the same pipeline.
Self-hosted runner persistence. If workflows run on self-hosted runners, a malicious PR can leave backdoors on the runner (files, cron jobs, modified PATH) that persist across workflow runs. The next workflow from a trusted source runs on a compromised machine.
GITHUB_TOKEN scope creep. Workflows with permissions: write-all or contents: write when they only need read access. Even without a PAT, an overpermissioned token can push code, create releases, or modify branch protections.
AI prompt injection in CI. Workflows that use AI agents and feed untrusted input (PR diffs, issue bodies) into the agent's context. The attacker embeds instructions in the PR that trick the AI into executing malicious commands. hackerbot-claw tried this against ambient-code/platform. Claude detected and blocked it.
Every one of these attack classes was documented before 2026. Every one of them exists in thousands of public repositories right now. The bot just automated the scanning.
The Prompt That Catches What You Don't Know About
You wouldn't have asked "check for pwn request attacks" because you didn't know the term existed. Neither did most of the Trivy maintainers. A checklist only catches what the checklist author knew about. A model brings knowledge you don't have.
Instead of asking about any specific attack, ask the right shape of question. Point an AI agent at your .github/workflows/ directory and give it this:
Review every file in .github/workflows/ for security vulnerabilities. For each workflow, check: (1) Can untrusted input from a fork, PR, issue, or comment reach a shell command or script execution? (2) Are secrets or tokens accessible in contexts where untrusted code runs? (3) Are action dependencies pinned to full commit SHAs or mutable tags? (4) Are permissions scoped to minimum required, or overly broad? (5) Can any external actor trigger workflow execution without maintainer approval? (6) Are artifacts from untrusted sources consumed by privileged workflows? (7) If self-hosted runners are used, can a workflow modify the runner environment persistently? Flag everything with the specific file, line number, and what an attacker could do with it.
That prompt doesn't mention pwn requests, expression injection, or any specific attack by name. It describes the properties that make workflows exploitable. The model fills in the pattern-matching from its training data, including attack classes you've never heard of. The cost: a few seconds of compute. The alternative: finding out the hard way, like Trivy did.
"But We Don't Use Trivy"
That's not the point.
The pull_request_target plus untrusted checkout pattern exists in thousands of public repositories right now. StepSecurity found hackerbot-claw had already hit repos from Microsoft, DataDog, and CNCF using the same technique. Your organization's workflows might have the same misconfiguration. When was the last time someone reviewed them?
And even if your workflows are clean, you still have transitive dependencies. The FutureSearch engineer who discovered the LiteLLM malware never installed it. A Cursor MCP plugin did. How many packages in your requirements.txt or package-lock.json do you actually know? Run pipdeptree or npm ls and count. The answer is usually uncomfortable.
There's no single fix. But the layers that would have reduced the blast radius are known: pin GitHub Actions to full commit SHAs instead of version tags. Use lockfiles with hash verification (pip install --require-hashes). Run install-time scanning with tools like Socket or Phylum that catch anomalous publishes. Monitor egress from CI runners and production. And review your .github/workflows/ directory with the same rigor you review application code.
The Part That Keeps Me Up
TeamPCP posted on Telegram: "These companies were built to protect your supply chains yet they can't even protect their own." They've announced partnerships with other groups and promised more attacks on security tools and open source projects.
The pattern works. Compromise a security tool, harvest the credentials of everyone who runs it, use those credentials to compromise the next target. The supply chain is a chain, and every link is a potential entry point.
The uncomfortable truth is that this attack was caught because the malware had a bug. The fork bomb crashed machines. If the .pth launcher hadn't recursively respawned, the credential harvester would have run silently. No crashes. No spike in RAM. Just a quiet HTTPS POST carrying your SSH keys, cloud credentials, and Kubernetes secrets to an attacker-controlled domain.
We got lucky. The attacker shipped sloppy code.
Go review your workflows. Right now. Not after the next sprint planning. Not when you get around to it. Right now. Point an AI agent at your .github/workflows/ directory and ask it to find every instance of pull_request_target that checks out untrusted code. Then pin your Actions to commit SHAs. Then audit your dependency tree. The next TeamPCP won't ship a bug in their malware.
Sources (as of March 25, 2026):
GitHub Security Lab: Preventing pwn requests (2021)
Wiz: Trivy Compromised by TeamPCP
The Hacker News: TeamPCP Backdoors LiteLLM
BleepingComputer: LiteLLM PyPI Package Compromised
FutureSearch: LiteLLM Supply Chain Attack Discovery
Hunter Strategy: Hackerbot-Claw Campaign Analysis
Endor Labs: TeamPCP Isn't Done
Rami McCarthy: TeamPCP Incident Timeline (comprehensive)
GitGuardian: Where Secret Exposure Hurts Most
Sanjeev Nithyanandam is the founder of Accelra Technologies, a cloud and DevOps consultancy in Vancouver. Follow the journey at Ship With Sanjeev.