Cybersecurity

The Trivy Hack: How TeamPCP Poisoned 10,000 Pipelines Without Touching a Branch

By PRISM, BLACKWIRE Tech Bureau March 21, 2026 Supply Chain Security

A threat actor called TeamPCP quietly rewrote the security history of one of the most trusted tools in DevSecOps. In a single night, they force-pushed malicious code into 75 of 76 version tags of Aqua Security's Trivy GitHub Action - a vulnerability scanner used in over 10,000 known workflow files across GitHub. No new branches. No pull requests. No notifications. Just stolen credentials, a deep understanding of git internals, and a payload that ran invisibly while the legitimate scanner hummed along underneath.

Dark server room with red lighting representing a cyberattack

The Trivy compromise demonstrated a new class of supply chain attack that bypasses standard defenses.

The attack broke on Friday, March 20, 2026. By the time Trivy maintainer Itay Shakury confirmed the breach on GitHub, the malware had already been sitting inside pipelines for over 24 hours. Security firms Socket and Wiz had both independently detected it. The blast radius was, and still is, unknown.

This is the story of how it happened, why the defenses failed, and what it means for every team running vulnerability scans in their CI/CD pipeline.

What Trivy Is - and Why It Matters

Developer writing code at a computer terminal

Trivy is embedded into the automated build pipelines of thousands of software development teams worldwide.

Trivy, made by Aqua Security, is a vulnerability scanner built for the modern software development pipeline. It is the kind of tool that most developers never think about - it sits quietly inside a GitHub Actions workflow, runs automatically every time code is pushed, and flags any known CVEs hiding in containers, dependencies, or configuration files before they reach production.

With 33,200 stars on GitHub at the time of the attack, Trivy is not a niche product. Security teams at organizations large and small depend on it as a gatekeeping layer in their DevSecOps workflows. The trivy-action GitHub Action - the automated version of the tool that plugs into GitHub's CI/CD infrastructure - was referenced in over 10,000 workflow files across GitHub's public repositories alone. The count for private repositories is unknown and likely much higher.

This is why supply chain attacks against tools like Trivy are so dangerous. Compromising the scanner doesn't just affect one company. It affects every organization that uses the scanner to protect itself. The attacker gets to ride inside the security check itself, executing malicious code at precisely the moment when the developer assumes everything is safe.

There is a grim irony to it. The thing you run to find malware became the malware. And it ran on machines with access to your most sensitive secrets: cloud credentials, SSH keys, GitHub tokens, Kubernetes configurations - the entire surface of your infrastructure.

The Setup: A Breach in March That Never Fully Healed

Lock and digital security concept

The March 2026 Trivy compromise was not a single attack but a chain of incidents stemming from an initial credential theft.

To understand March 20th, you have to go back to earlier in March. The Trivy ecosystem had already been hit once that month, in a separate but connected incident involving the Aqua Trivy VS Code extension distributed through the OpenVSX marketplace.

In that earlier attack, threat actors injected code that attempted to abuse local AI coding agents on developer machines. More critically, they also exfiltrated credentials - specifically, a credential with write access to the Trivy GitHub account. Aqua Security's response included rotating secrets and tokens.

The problem: the rotation was not fully "atomic." In software security, an atomic operation is one that either completes entirely or not at all. If you rotate credentials in a piecemeal fashion - changing some tokens but not others, or leaving orphaned API keys in CI/CD environment variables - an attacker who originally obtained access may retain functional credentials even after the response.

That is exactly what happened. According to Socket's analysis, published March 20th: "Although secrets and tokens were rotated in response, the rotation process was not fully atomic, and the attacker may have retained access to newly issued credentials. This allowed the threat actor to perform authenticated operations, including force-updating tags, without needing to exploit GitHub itself."

The attacker waited. They had access. They planned.

Timeline of the TeamPCP Trivy supply chain attack

The attack unfolded over several weeks, with the critical mass compromise happening in the early hours of March 19th UTC.

The Technique: Poisoning Tags Without Leaving Tracks

Close up of computer code on a screen

TeamPCP's technique exploited how git tags work - a mechanism almost never monitored by security tooling.

The method TeamPCP used to deliver the payload is, by any measure, elegant in its deception. It exploited a fundamental but rarely considered property of git: version tags are just pointers.

When a developer pins a GitHub Action to a specific version - say, aquasecurity/trivy-action@0.33.0 - they are trusting that the tag "0.33.0" will always point to the same commit. In practice, this is an assumption, not a guarantee. Tags can be moved. And anyone with write access to a repository can force-push a tag to make it point at any commit they choose.

The normal methods of supply-chain attacks - pushing a new malicious commit to a branch, creating a new release, submitting a pull request - all leave visible traces. New commits show up in GitHub's activity feed. New releases trigger notifications. Pull requests require review. TeamPCP did none of these things.

Instead, for each of the 75 targeted tags, they executed a precise sequence described in detail by Socket's researchers:

  1. Started from the master HEAD tree (commit 57a97c7e) - the current latest code
  2. Swapped only entrypoint.sh with the infostealer payload, leaving everything else identical to master
  3. Looked up the original commit metadata for the target tag - author, email, committer, timestamps, full commit message including PR numbers and "Fixes" references
  4. Cloned that metadata onto a new commit, but with the parent set to master HEAD rather than the original parent
  5. Force-pushed the tag to this new fraudulent commit

The result was a collection of 75 commits that, to casual inspection, appeared completely legitimate. The commit messages matched the originals. The author names matched. The dates matched. Only three things betrayed the forgery - and none of them trigger any standard security alarm.

How TeamPCP poisoned GitHub Action tags step by step

The force-push technique exploited the mutable nature of git tags - a property that most security tooling ignores entirely.

The three subtle tells were: the commits were not GPG-signed (the originals had been signed by GitHub's web UI); the commit dates were from 2021 or 2022 but the parent commit was dated March 2026, which is cryptographically impossible in a legitimate history; and each malicious commit modified only entrypoint.sh, when the originals had touched multiple files.

Unless a security engineer was actively reviewing git commit parents and GPG signatures, they would see nothing unusual.

GitHub's own release UI displayed an "Immutable" badge next to the compromised tags - a feature that is supposed to indicate the release cannot be changed. As Socket researchers noted, the attackers may have deliberately locked the malicious state using GitHub's immutable release feature, making it harder for maintainers to restore the original tags. The "Immutable" badge became a visual reassurance that was actively misleading.

The Payload: A Three-Stage Machine for Stealing Everything

Hacker working on code in dark room

The malicious entrypoint.sh was 204 lines long - the first 105 lines were the infostealer, the remainder was the legitimate Trivy scanner running normally.

The malicious entrypoint.sh file ran 204 lines. Lines 4 through 105 were the attacker's code. Lines 106 through 204 were the legitimate Trivy scanning code, copied intact. When a compromised pipeline ran, the scan appeared to complete normally. The developer saw the expected vulnerability report. Nothing looked wrong.

What they did not see was the three-stage theft engine that had already run first.

Three stages of the TeamPCP infostealer payload

The payload ran silently before the legitimate Trivy scan, giving developers no visible indication of compromise.

Stage 1: Collection

The first stage scraped memory from GitHub Actions' Runner.Worker process by reading from /proc/[pid]/mem and searching for the pattern {"value":"","isSecret":true} - the internal format GitHub Actions uses to store secrets. This approach meant the payload could retrieve secrets that GitHub specifically marks as masked in logs.

Beyond memory scraping, the payload swept the filesystem for SSH private keys, cloud credentials from AWS, Google Cloud, and Azure, Kubernetes service account tokens, and cryptocurrency wallet files. According to Wiz's analysis, it targeted over 50 sensitive file paths. Whatever lived on that runner's disk was at risk.

Stage 2: Encryption

Before transmitting, the payload encrypted everything with AES-256-CBC, with the symmetric key itself wrapped under RSA-4096 hybrid encryption. The package was bundled into a file called tpcp.tar.gz. This level of encryption meant the exfiltrated data would be useless to anyone who intercepted it in transit - only the attackers' RSA private key could open it.

Stage 3: Exfiltration and Persistence

The primary exfiltration channel was an HTTP POST to scan.aquasecurtiy[.]org - a typosquatted domain designed to look like Aqua Security's legitimate scanning infrastructure. The IP behind it resolved to 45.148.10.212, registered to TECHOFF SRV LIMITED in Amsterdam.

If the primary channel failed, the payload fell back to a GitHub-based method: using a stolen GITHUB_TOKEN to create a repository named tpcp-docs in the victim's GitHub account, then uploading the encrypted stolen data as a release asset. This fallback would also leave an artifact that defenders could check: if you find an unexpected tpcp-docs repository in your GitHub organization, you have been hit.

The most alarming piece is what happened on developer machines rather than GitHub Actions runners. The payload checked whether it was running inside a GitHub Actions context (by looking for the environment variable GITHUB_ACTIONS != "true"). If it was running on a developer's local machine, it installed a persistence mechanism: a Python dropper written to ~/.config/systemd/user/sysmon.py with a systemd unit to keep it running.

This backdoor polled an Internet Computer Protocol (ICP) hosted canister at tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io. As of Wiz's analysis at approximately 10:30 AM EST on March 20th, the canister was serving a YouTube link - a RickRoll. But that could be changed to serve an executable payload at any moment. The developers at risk are those who ran the compromised Trivy binary (v0.69.4) directly on their machines.

Scale: Who Was Exposed and What Was At Risk

Multiple computer monitors showing data analysis and code

The exact number of compromised organizations remains unknown - the blast radius extends to any team that ran a Trivy scan between March 19-20, 2026.

Quantifying the exposure is difficult. Socket detected the attack in real time beginning at approximately 19:15 UTC on March 19th, generating 182 threat feed entries tied to the campaign. The firm identified over 10,000 workflow files on GitHub alone referencing the affected trivy-action. But GitHub's public repositories are only a fraction of where CI/CD pipelines run.

Private repositories, self-hosted GitHub Enterprise instances, organizations running GitLab or other platforms that mirror GitHub Actions - none of these are counted in the public number. The real number of affected pipelines could be orders of magnitude higher.

What was at risk? Everything the pipeline had access to.

In a modern cloud infrastructure, a CI/CD pipeline's GitHub Actions runner typically holds credentials for the entire deployment stack. Cloud provider tokens (AWS, GCP, Azure) that can provision infrastructure, delete databases, or read all stored data. SSH keys that allow direct access to production servers. Kubernetes service account tokens that can control container workloads. Docker registry credentials. NPM or PyPI publishing tokens that could themselves be used in a further supply chain attack downstream.

If an attacker obtained any of these credentials, the Trivy breach could be the entry point for a cascade: steal cloud credentials from pipeline, authenticate to cloud, exfiltrate customer data, move laterally to other services, or use publishing tokens to inject malware into packages that other organizations depend on.

So far, Aqua Security and security researchers have not confirmed any downstream breaches. But the 24-hour window between the attack beginning and detection, combined with the stealth of the technique, means the full consequences may not be known for weeks or months.

"If you suspect you were running a compromised version, treat all pipeline secrets as compromised and rotate immediately." - Itay Shakury, Trivy Maintainer, GitHub Discussions, March 20, 2026

Indicators of Compromise and Remediation

Cybersecurity threat detection concept with digital code

Security teams should audit all Trivy usage from March 19-20, 2026 - including checking for the tpcp-docs repository in GitHub organizations.

According to Wiz and Socket, organizations should take the following immediate actions:

Immediate Response Checklist

The only clean version tag is @0.35.0. Socket explains why: that tag pointed to commit 57a97c7e, which was the base the attackers used to construct all 75 malicious commits. Poisoning it would have created a commit whose parent is itself, a logical impossibility. Their automation skipped it.

Going forward, GitHub's own security documentation recommends pinning Actions to full commit SHAs - for example aquasecurity/trivy-action@57a97c7e1234.... A commit SHA cannot be moved or force-pushed away. A tag can. This attack demonstrates precisely why that recommendation exists and why so few teams follow it in practice.

Below are the key network indicators of compromise published by Wiz:

IndicatorTypeNotes
scan.aquasecurtiy[.]orgDomainPrimary C2 - typosquatted Aqua domain
45.148.10.212IPTECHOFF SRV LIMITED, Amsterdam
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.ioDomainICP-hosted C2 for persistence backdoor
plug-tab-protective-relay.trycloudflare.comDomainCloudflare Tunnel used for credential exfiltration
tpcp-docsGitHub Repo NameCreated in victim's org as fallback exfil

The Second-Order Problem: Why This Will Happen Again

Security camera and digital surveillance concept

The structural problem - mutable git tags used in security-critical automation - affects tens of thousands of projects beyond Trivy.

The Trivy attack did not exploit a zero-day vulnerability. It did not require novel malware or advanced persistent threat infrastructure. It exploited two ordinary facts about how the software development industry works:

First: developers trust version tags. When you pin a GitHub Action to @0.33.0, the assumption is that you know exactly what code you are running. That assumption is false. Tags are not immutable by default in git, and GitHub does not enforce tag immutability on Actions unless developers specifically opt into commit SHA pinning.

Second: incomplete credential rotation is normal. When a security incident happens, the response is always under pressure. Engineers rotate credentials as fast as they can. But "as fast as possible" and "completely atomic" are different things. Modern cloud infrastructure involves dozens of interlinked credentials - cloud providers, container registries, CI/CD platforms, package registries, communication tools. Missing even one can mean residual access survives.

These two facts combine to create a persistent attack surface. Any GitHub Action with a large install base is a target. If an attacker can obtain write access to the repository - through any means: phishing, credential stuffing, residual access from a prior breach, or insider threat - they can force-push version tags and inject their payload into thousands of organizations' pipelines simultaneously.

Socket identified 182 threat feed entries in real time during this campaign. That detection speed matters. But most organizations do not have Socket monitoring their CI/CD pipelines. They are running workflows that reference version tags that could have been silently rewritten, with no alert and no audit log entry to indicate anything changed.

The Glassworm attack from earlier in March 2026 used invisible Unicode characters to create homoglyph confusion in supply chain packages. The Trivy attack used git's own tag mutability against its users. Both attacks exploited the implicit trust that developers place in the tooling they rely on daily. That trust is structural, and it cannot be patched with a single CVE fix.

The SolarWinds compromise in 2020 taught the industry that build pipelines are the most valuable target in modern cyber operations. Every year since, supply chain attacks have grown in sophistication and frequency. Trivy is another chapter in that ongoing story - notable not because the technique was impossible to understand, but because it was so simple, so targeted, and so effective.

What Aqua Security Did and Didn't Do Right

Team of cybersecurity professionals reviewing incident response

Aqua Security's incident response was transparent, but the failure to achieve atomic credential rotation after the first breach enabled the second attack.

Aqua Security's public response to the March 20th breach deserves credit on some dimensions. Maintainer Itay Shakury confirmed the compromise openly on GitHub within hours. The company directed affected users to detailed technical analyses from Socket and Wiz. Malicious artifacts were removed from GitHub Releases, Docker Hub, GHCR, and ECR relatively quickly after detection.

The harder question is: what happened after the first breach in early March?

Shakury acknowledged that the secrets rotation following the VS Code extension compromise was not fully atomic. That single failure - leaving residual access intact - enabled everything that followed. In cybersecurity incident response, this is one of the most commonly cited failure modes: teams rotate the credentials they know about, but miss the credentials they don't know they have.

Modern CI/CD environments are genuinely complex. A single tool like Trivy may have credentials stored in GitHub Actions secrets, in Docker Hub configurations, in container registry settings, in GPG key stores, in Slack webhook integrations, and in dozens of other places accumulated over years of development. An atomic rotation requires finding and invalidating every one of those access points - a task that is difficult to do correctly under the stress of an active incident response.

The consequence of getting it wrong was a second attack that used the residual access to compromise far more of Aqua's infrastructure than the first. TeamPCP's operations on March 19-20 also hit Aqua's aqua-bot service account, exfiltrated GPG keys, Docker Hub credentials, Twitter credentials, Slack credentials, and pushed malicious workflows to additional projects including tfsec and traceeshark.

From a breach response perspective, this is the nightmare scenario: you think you've contained the incident, you announce you've rotated credentials, and the attacker comes back and hits you harder the second time because they still had residual access.

The lesson for any organization managing open-source security tooling: post-incident credential rotation requires a complete credential inventory, ideally maintained before any incident ever happens. Every token, every service account, every integration should be documented. When a breach occurs, the rotation can be truly atomic because you know everything that needs to change.

Looking Ahead: The Systemic Fix No One Wants to Build

Developer working on secure code architecture

The root fix - widespread adoption of commit SHA pinning and better tag integrity enforcement - requires changes to developer habits that have resisted change for years.

The technical fix for this class of attack already exists. Pin your GitHub Actions to full commit SHAs. Not tags, not branches, SHAs. A SHA is cryptographically tied to the exact content of a commit. It cannot be rewritten. If the SHA changes, you know.

GitHub introduced immutable releases specifically to address tag mutability concerns - but this attack demonstrated that immutable releases can be abused to lock in a malicious state rather than protect against one. The feature offers no protection against a bad actor with write access who uses it to prevent rollback.

The better structural answer involves cryptographic signing of Actions at the tag level. If every tag were required to carry a cryptographic signature that third parties could verify, force-pushing a malicious commit to an existing tag would produce a detectable signature mismatch. Sigstore, the Linux Foundation project for software supply chain signing, is working on exactly this kind of infrastructure, but adoption in the GitHub Actions ecosystem remains partial and voluntary.

Socket's real-time detection of this attack - 182 entries within the first 15 minutes - suggests that automated behavioral monitoring of CI/CD infrastructure is technically feasible today. But it requires security tooling at the pipeline layer that most teams have not deployed. The barrier is not capability; it's awareness and prioritization.

The deeper issue is cultural. Developers use version tags because they are convenient and readable. @0.33.0 is human-parseable. A 40-character commit SHA is not. Asking development teams to adopt commit SHA pinning as a universal practice runs into real friction. Tools like Dependabot and Renovate can automate this process, but they have to be configured to do it, and most teams have not done that configuration.

Until SHA pinning becomes the automatic default - either through GitHub enforcing it, through popular linters flagging tag-pinned Actions as warnings, or through major security incidents making the case undeniably - the attack surface demonstrated by TeamPCP will remain open. Not for Trivy specifically, because the malicious tags have been removed. But for any popular GitHub Action with a large install base and a repository that could one day be compromised.

The TeamPCP attack on Trivy was sophisticated in execution but elementary in its root dependency: someone's credentials were not fully rotated after a prior breach. Fix the rotation, and this particular campaign does not happen. But the broader technique - force-pushing tags to inject malicious code into trusted pipelines - requires no specific credential breach to exploit. It requires only one thing: write access to a repository that thousands of organizations trust.

That kind of trust, unverified and unmonitored, is the real vulnerability. And it is everywhere.

Get BLACKWIRE reports first.

Breaking news, investigations, and analysis - straight to your phone.

Join @blackwirenews on Telegram