Emil Brasø

Senior Platform Engineer

Taking a look at the Trivy Attack

Let’s take a look at what happened and what measures you can take to prevent similar incidents from happening to you 👇

At the end of March, I posted on my network that the popular security scanning tool Trivy was the subject of a supply chain attack.

Since then, there have been developments, and many downstream users of Trivy have been affected, with some sources even claiming that over 1,000 SaaS products were impacted by the end of March.1

Even now, in June, we are seeing many attacks on GitHub-hosted projects, using many of the same attack vectors. The original attackers, Team PCP, also continue to proliferate.2

Recently, we’ve also learned that the Tanstack NPM packages were breached in the same way as Trivy.3

Due to the popularity of the Trivy project, many users were vendors or other projects themselves. The impact has had a cascading effect due to the attackers leveraging a single set of stolen credentials to spread even further.

For the purposes of this blog post, however, we will focus primarily on the compromise of the Trivy Repo and what allowed it to happen. There are a lot better writers out there about the threat landscape and implications beyond this scope 👀

I’ll also assume you have a basic understanding of GitHub Actions.

After reading, I hope you understand how the compromise was possible and are better equipped to protect your own organization against such attacks and their impacts.

About the attack

Let us take a look at the attack itself.

Trivy is a very popular Security scanner, widely used by cloud native projects and the like. The project is Open Source (great!), and under the embrace of Aqua Security.

You absolutely should use tools like these; they are a very efficient way to iron out security flaws and misconfiguration in your projects.

Timeline

To help us out, I made this quick infographic outlining the timeline:

Credits: Icons courtesy of heroicons.com4 and tech-stack-icons.com5, infographic made by Emil Brasø

  • In late February, attackers compromised an insecure GitHub Action in the Trivy repo, exfiltrating a Privileged Access Token (PAT).
    • We will take a look at what made the Action insecure in just a moment.
  • 1. March, the Trivy team disclosed this and attempted credential rotation.
  • 19. March (about 17 UTC), due to credential rotation not being sufficiently done, the attackers exploited the PAT to overwrite almost all tags on the repo to point to malicious commits.
  • 19. March (about 20 UTC), Trivy discovered and contained the attack.

For a bit of a deeper dive, Aqua Security lays out the timeline pretty well on their own site: https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/

Users who pulled a tagged version of Trivy during the window of compromise downloaded a compromised version designed to steal all credentials it could find on the system running Trivy.

This included not only secrets such as SSH keys but also environment variables. For users running Trivy in GitHub Actions (very common), the malicious versions would also retrieve contents such as repository secrets, GITHUB_TOKEN, etc.

The malicious code would simply scrape and collect everything it could.

Other major open-source projects have had compromises due to this; a well-known example is litellm6.

Litellm ran an affected version of Trivy, resulting in credentials being stolen. Attackers were then able to compromise litellm’s packages on PyPi with the same credential-stealer, further spreading the compromise.

Another example of further spreading was the breach of Checkmarx KICS, another security tool. This helped further spread the chain of compromises7

For household names, Cisco reportedly had source code stolen as a consequence of the Trivy attack8. Yes, that Cisco. If nothing else, this should show how widespread Trivy was used at the time of compromise.

In any case, we very likely have not yet seen all the impact yet, but already by the end of March, cybersecurity firms reported they had seen the compromises being actively used for extortion9

What allowed the attack to happen?

What was it with the setup on the Trivy repo that allowed this to happen?

GitHub triggers

Primarily, the compromise was due to the Trivy repo using the pull_request_target trigger without the proper safeguards, in one of its workflows.9

The pull_request_target trigger in GitHub Actions allows forks to run a workflow in the upstream repository11. Proper security controls were not in place for securing that this did not allow running untrusted code (likely, the pr-name could contain untrusted code).

The intent of using the trigger itself was good, as it can be used to subject forks to tests and similar in the same way as the upstream repo.

Here, this allowed the attackers to grab secrets from the runners the workflows ran on, enabling PATs and other sensitive secrets to be stolen.

The Trivy maintainers later stated that they had removed all uses of pull_request_target triggers and taken additional steps to ensure sufficient credential isolation.

A compromise through this trigger is not unique to Trivy. We recently learned that the tanstack npm packages were compromised this way, too.12


GitHub Secrets

Trivy was quick to rotate these secrets, but as we later learned, this process was incomplete, allowing the attackers to exploit credentials that had not been sufficiently rotated.


GitHub Tags and Releases

The attackers were able to maintain a foothold through incomplete credential rotation, and had access enough to:

  1. Publish new commits containing some Python code that would steal credentials
  2. Overwrite almost all tags and releases to point to these malicious commits.
  3. They were also able to push new container images to Docker Hub and other registries with the malicious code, but tag overwriting was not possible here.13
    • This was possible because the compromised GitHub repo included the CI/CD pipeline that pushed images to the container registries Trivy used.

Aftermath

After the actual repository takeover, the Trivy Team acted quickly to regain control of the repo and restore all affected versions. They have been very transparent, publishing detailed reports and advisories on what happened.

Being transparent here was absolutely the best move, especially given Trivy’s position in the ecosystem.


Guarding yourself against supply-chain attacks

Okay, now that we know what happened, let’s look at some measures we, as consumers, can take. This list is not exhaustive, but outlines some common measures.

Pinning dependencies to commit hashes

Trivy (and other such projects) is distributed to users in a number of ways:

  1. A GitHub action that users could call from their GitHub workflow
  2. A Trivy container image
  3. A Trivy executable you can download from the repo

During the compromise, the attackers overwrote almost all existing tags and releases on the Trivy repo and pointed those at commits containing malware.

If you were pulling Trivy from the Trivy repos, simply pinning your dependencies to tags wouldn’t be enough. Because those tags would now point to new, compromised commits.

In other words, what you got while pulling Trivy v0.63 before wouldn’t be the same when pulling again during the compromise window.

The Trivy team itself could have activated release immutability on its GitHub repository. This setting greatly helps in scenarios like these, as tags and releases can’t be overwritten, and an additional attestation is attached to the release for verification purposes.14

In this compromise, the attackers released their malicious commits as immutable tags, which, in this case, lent them false credibility. This goes to show that even immutable releases should not be enough for us to trust a given release.15

For most users, the best way to ensure we use the same content at all times is to use commit hashes.

Using commit hashes ensures that we get the exact content we reference, as the hash provides a cryptographic guarantee of its integrity. This guarantee is useful, even though it says nothing about who wrote the contents of that commit; it simply ensures the contents have not been tampered with.

Pinning to commit hashes is a best practice in pretty much all ecosystems and is outlined in GitHub’s secure use reference15.

Usage of Secrets and credentials

If the secrets stolen from Trivy were benign or limited in scope, the blast radius would have been far smaller, so that brings us to three pieces of advice:

  1. Treat GitHub runners as an untrusted environment.
    • The context in which a workflow runs should have just the privileges it explicitly needs.
    • The same goes for which secrets and environment values runners can access.
  2. Minimize access to secrets by:
    • Not using org-scoped secrets
    • Using Secrets inside GitHub Environments with Approval gates to restrict access to these secrets to just when it’s needed and approved
  3. Do not use long-lived credentials.
    • Many vendors now support OIDC and federation-based authentication, using trust relationships instead of passwords. If you don’t have a password, you can’t lose it 🤷.16
  4. Likewise, minimize the usage of credentials with broad permissions.

In GitHub, the context with which a workflow is run matters a lot, and it impacts what secrets and tokens is available, so administrators should put due dilligence into understanding GitHub context.17

Transient dependencies

On Hacker News and other platforms, after this, some people rightfully pointed out that trusting tags for GitHub Actions (e.g., the Trivy action) may compound a false sense of security.

It is clear that we can not trust an Action without trusting all its dependencies, or, for that matter, the manner in which some Actions pull their own dependencies. (Some actions use Curl during runtime, others reference latest tags 😵‍💫)

Obviously, using Actions like those is not ideal. I would advise against using GitHub Actions from untrusted groups or GitHub Actions you have not verified yourself.

Regardless, I would claim that nested dependencies are an industry-wide problem.

For the GitHub Actions ecosystem specifically, we should use GitHub’s systems to verify and control actions.

If an Action is verified, GitHub confirms who published and authored it, which is a good feature. But you should still understand what an action does under the hood before using it in your workflow. Luckily, all the source code for GitHub Actions you can use from third parties is open source, so you can read and verify it before use.

For enterprises, we also have the option to only allow workflows to call pre-approved Actions or those under the «GitHub verified Actions» banner.

For big organizations with the manpower and skills to maintain pre-approved lists, this could greatly improve the security posture – even if I would be the first to claim that pre-approved lists often are a slippery, unmaintainable slope for a centralized IT organization.

Misconfigurations

Misconfiguration is another thing. For Trivy, the insecure pull_request_target trigger was the original root cause.

It is well known that this trigger poses a security risk, and GitHub’s secure usage pages explicitly mention it. Trivy itself also stated after the incident that they have improved their usage of linters to ensure proper CI/CD authoring.18

To help us avoid misconfiguration, we should also consider using Static Code Analysis tools such as Checkov19 to iron out misconfigurations in our GitHub Workflows. With the above-mentioned transient dependencies, «just» scanning our local usage or just the actions we author ourselves is not enough on its own.

I use Checkov all the time through pre-commit hooks myself. I made a post about how to do this a couple of years back, actually. (shameless self promotion )

Finishing checklist (you made it!)

Before finishing, let us summarize what we’ve learned here into two distinct checklists.

What can you do as a consumer:

  1. Ensure to use commit hashes instead of mutable tags when referencing a release.
  2. Treat runners as untrusted environments.
  3. Minimize the usage of long-lived (and therefore breachable) credentials.
  4. Grant credentials and workflows just the permissions they absolutely need.
  5. Organizations may opt to allow only trusted or GitHub-verified actions to run within their organization.
  6. Run Static Code Analysis tools to protect against misconfigurations (such as Checkov with pre-commit hooks)

And;

What can you do as a maintainer:

  1. Exercise great care when using the pull_request_target workflow trigger and other triggers that utilize the GitHub Event context.
    • If that context is needed, ensure it is sufficiently sanitized and conforms to secure use.
  2. Maintainers can help ensure tag immutability by enabling the immutable releases option on their repository.
  3. Run Static Code Analysis tools to protect against misconfiguration (such as by using checkov with pre-commit hooks)

And.. so much more! In this ever-changing, fast-moving industry, we need to continuously maintain a strong posture and stay up to date with the threats out there.

Closing notes

We have covered a lot here. It’s clear that this type of attack is prevalent in 2026 and that supply chain attacks have far-reaching consequences. Using even the right tool at the wrong time can result in a breach, no matter how popular and trusted that tool is.

In the end, there are many measures we can take to ensure we are not subject to such attacks and are not impacted by someone else’s breach either.

While I purposely avoided talking about the broader ecosystem here, I hope this served as a good introduction to what happened during these attacks and how you can protect yourself.

Feel free to leave me any feedback. Have a good one!

Footnotes

  1. Not a first-hand source, but both sans.org and cyberscoop articles cite that mandiant claims there has already been upward of a 1000 impacted enterprise environments ↩︎
  2. An example for a news-story involving Team PCP https://thehackernews.com/2026/05/github-investigating-teampcp-claimed.html ↩︎
  3. https://tanstack.com/blog/npm-supply-chain-compromise-postmortem ↩︎
  4. https://heroicons.com/outline ↩︎
  5. https://www.tech-stack-icons.com/ ↩︎
  6. https://github.com/BerriAI/litellm/issues/24512 ↩︎
  7. https://checkmarx.com/blog/ongoing-security-updates/#:~:text=What,artifacts ↩︎
  8. https://www.safestate.com/post/cisco-source-code-stolen-in-trivy-supply-chain-attack ↩︎
  9. https://www.sans.org/blog/when-security-scanner-became-weapon-inside-teampcp-supply-chain-campaign#:~:text=As%20of%20March,to%205%2C000%2D10%2C000. ↩︎
  10. https://github.com/aquasecurity/trivy/discussions/10462 ↩︎
  11. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target ↩︎
  12. https://tanstack.com/blog/npm-supply-chain-compromise-postmortem ↩︎
  13. https://www.docker.com/blog/trivy-supply-chain-compromise-what-docker-hub-users-should-know/ ↩︎
  14. https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases ↩︎
  15. https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/#:~:text=release%2E-,GitHub,protection ↩︎
  16. https://docs.github.com/en/actions/reference/security/secure-use#using-third-party-actions ↩︎
  17. This is supported by a lot of vendors, such as Azure and Amazon ↩︎
  18. https://docs.github.com/en/actions/reference/workflows-and-actions/contexts ↩︎
  19. https://github.com/aquasecurity/trivy/discussions/10462 ↩︎
  20. https://www.checkov.io/ ↩︎

Leave a comment