When the security scanner is the attack: the Trivy action compromise

What the March 2026 Trivy compromise changed, what it took from build pipelines, and the checks that tell you whether your own repositories were in range.

Timothy Lindblom

Founder, Newly

Published Last updated

In March 2026 an attacker holding credentials left over from an earlier incident moved 76 of the 77 version tags of trivy-action, a GitHub Action many teams run in CI, onto code that steals secrets. A workflow that used a moved tag during the window handed its secrets over. Check your run history for March 19 and 20 (UTC), then rotate what those jobs could read.

What happened to Trivy?

Trivy is a vulnerability scanner from Aqua Security that teams run in their build pipelines. That position is the reason it was worth attacking: a job that scans your code is trusted with your code and the secrets around it. Microsoft attributes the activity to a group it tracks as TeamPCP. Aqua's advisory (CVE-2026-33634, rated critical, published March 21, 2026) lists three affected components.

Affected Trivy components and windows
ComponentAffectedWindow (UTC)Fixed or unaffected
trivy-actionVersions before 0.35.0March 19 about 17:43 to March 20 about 05:400.35.0
setup-trivyVersions before 0.2.6March 19 about 17:43 to about 21:440.2.6
trivy binaryv0.69.4March 19 18:22 to about 21:42v0.69.2, v0.69.3
Docker Hub imagesv0.69.5 and v0.69.6March 22 15:43 to March 23 about 01:40v0.69.3

The advisory states the root cause plainly. An earlier incident was answered with a credential rotation that was not atomic, meaning not every credential was revoked at the same moment, so the attacker could keep using a still-valid token to capture newly rotated secrets. Microsoft's write-up adds that the attacker force-pushed malicious commits onto existing tags: 76 of 77 trivy-action tags and all seven setup-trivy tags.

According to the advisory, the injected code read the memory of the GitHub runner process, searched more than 50 file locations for SSH keys, cloud credentials, Kubernetes tokens, Docker configuration and .env files, and, when sending the data out failed, created a public repository named tpcp-docs on the victim's GitHub account to hold it.

Why was a moved tag enough to reach my secrets?

A workflow line such as owner/action@tag tells GitHub to fetch whatever that tag points at on the day the job runs. Your repository does not change when the tag moves, so nothing shows up in a pull request or a diff. GitHub's secure use reference says a tag can be moved or deleted if someone gains access to the repository storing the action, and recommends pinning to a full-length commit SHA instead.

Four steps: your workflow names an action by tag, the tag is moved to attacker code, the job runs it with your secrets, the stolen secrets leave the runner.Your workflowuses action@tagTag is movedto attacker codeJob runs itwith your secretsSecrets leavethe runnerNothing in your repository changes between step 1 and step 3.A full commit SHA in step 1 is the part of this chain you control.

The second half of the problem is what the job can see. GitHub notes that an action can reach the workflow token through the github.token context even when you never pass it in, and the advisory says the injected code read the memory of the runner process itself. A scanner that runs inside your build therefore sits next to everything the build can read.

One check Dependabot does not make

GitHub documents that Dependabot alerts only cover actions that use semantic versions and are not raised for actions pinned to a SHA. If you pin, you take on the job of updating the pin on purpose.

Why does this matter if I build apps rather than security tools?

Because the pipeline that builds an app holds the keys to ship it. If you download your project code or connect your own repository to a Newly project, the CI around it is yours, and it may keep an Expo access token, a store upload credential, an AI provider key and a database service key near that pipeline. Expo's documentation states that anything included in client-side code should be considered public, and that secret-visibility variables exist to give values to build and workflow jobs. The job is the audience, so code that runs in the job is too.

The Trivy compromise also travelled. According to the GitHub advisory for litellm, LiteLLM versions 1.82.7 and 1.82.8 were uploaded to PyPI after an API token was exposed through an exploited Trivy dependency. PyPI's incident report says the same chain led to the telnyx package, and recommends dependency cooldowns, lock files with hashes and Trusted Publishers. The full story of that package is on our LiteLLM page for app builders.

LiteLLM was compromised again in October. At the time of writing on October 21, 2026, Datadog Security Labs stated that no connection between the two compromises had been established, and LiteLLM's own post was marked as an investigation in progress. Treat the two incidents as separate until a primary source says otherwise.

How do I check my own repositories?

None of this needs special tools. You are looking for three things: which actions you reference, how you reference them, and whether any job ran an affected one in the window.

1. List every action you use

In each repository, search the .github/workflows folder for lines that start with uses:. Search the same folder for aquasecurity. Do this for the repositories of every project and every client app, including ones you stopped touching.

2. Read the history for March 19 to 23

Open the Actions tab and filter runs by date. Any run on March 19 or 20 (UTC) that used trivy-action or setup-trivy is in range. Runs on March 22 and 23 matter if a job pulled the Trivy Docker image. The setup step of a run log lists the actions it downloaded. Keep the logs you read, because they are your owner evidence.

3. Look for the fallback repository

Aqua's advisory says to search your GitHub organization for a repository named tpcp-docs. Search each personal account and organization that owns a repository with an affected run. Finding one you did not create means detected. Not finding one leaves you at unknown, because the fallback only ran when the first method failed.

What each finding means
What you foundStateWhat to do
An affected run in the window, or a repository you did not create named tpcp-docsDetectedTreat every secret that job could read as exposed and rotate it. Keep the run logs.
A trivy-action reference that uses a tag, with no run history to readUnknownRotate the secrets that workflow can read. Absence of logs proves nothing.
No Trivy reference and no run in the windowUnknown for other actionsThis clears Trivy only. Apply the same tag check to every other action you use.
Affected run, secrets rotated together, old keys shown refused by the providerConfirmed by owner evidenceKeep the audit log entries and move on to the changes below.

What should I rotate, and in what order?

Aqua's advisory is direct: all secrets accessible to affected pipelines must be treated as exposed and rotated. It also names the mistake that let the first incident continue, which is a rotation that was not atomic. Plan the swap before you start so that the old values die together.

  1. Write the list first: repository and environment secrets, the organization secrets that repository can read, and anything the runner could reach from disk.
  2. Create every replacement, store it where the workflow reads it, and confirm one clean build.
  3. Revoke all the old values in one sitting, then read the provider audit logs for use after the revocation.
  4. Put signing and store credentials, cloud keys and AI provider keys at the top, since those cost money or let someone publish as you.

Our page on rotating secrets after a platform breach has a longer worksheet, and red.run.cloud has a rotation guide for sites. For a related case where the fake action was a "security audit", see red.run.cloud's page on GhostAction, and for dependency worms, the ChainDrop check.

What should I change in my workflows?

Changes to workflow files, with the source for each
ChangeWhat it limitsSource
Pin each third-party action to a full commit SHAA moved tag can no longer change what your job runsGitHub secure use
Enforce SHA pinning in the allowed actions policyWorkflows that use an unpinned action failGitHub changelog, August 15, 2025
Set a permissions block with contents: readWhat a stolen workflow token can changeGITHUB_TOKEN docs
Scope secrets to an environment, not the whole repositoryWhich jobs can read a given secretUsing secrets
Publish packages through a trusted publisherA long-lived token that outlives the job; PyPI tokens minted this way expire after 15 minutesPyPI Trusted Publishers

Update pins deliberately. A weekly pull request that bumps each pin, read by a person, replaces a tag that updates itself. For the Newly-built part of your project, the same rule holds for the dependencies in a downloaded or connected repository.

What a website scan can and cannot tell you here

Red by run.cloud reads a live site from outside. It cannot see a build pipeline, a workflow file or a run log, so it cannot say whether an action ran in your CI. It can show whether the site that pipeline deployed serves keys, .env files or readable source maps, which is a separate question worth asking after any build-secret scare.

Where do you stand?

Everything starts as unknown, because that is what an unchecked item is. Move an item to confirmed only when you hold the evidence listed under it. For the wider app check, see the 15-minute check for an AI-built app.

Your pipeline check

  • Detected: You found the problem.
  • Unknown: Not checked yet, or the check could not tell.
  • Confirmed by owner evidence: You checked and kept the proof.
  1. 1. No workflow in any of my repositories referenced aquasecurity/trivy-action or setup-trivy during March 19 to 20, 2026 (UTC), or I checked the runs that did.

    Evidence: the search result across your repositories and the run list for those two days.

  2. 2. My GitHub account and organizations hold no repository named tpcp-docs that I did not create.

    Evidence: a search of your repositories and an organization audit log.

  3. 3. Every third-party action in every workflow is pinned to a full commit SHA.

    Evidence: the list of uses lines, each ending in a 40-character commit SHA.

  4. 4. Workflows run with a read-only GITHUB_TOKEN unless a job asks for more.

    Evidence: the permissions block at the top of each workflow or the repository default.

  5. 5. Secrets that an affected job could read were revoked together and replaced, with the old values confirmed dead.

    Evidence: the date of the rotation and the provider's audit log showing the old keys refused.

  6. 6. Package and store publishing uses short-lived tokens, or the long-lived token has been replaced since March 2026.

    Evidence: the trusted publisher setting or the token creation date.

0 detected6 unknown0 confirmed by owner evidence

Your answers stay in this browser tab. Nothing is saved or sent.

Frequently asked questions

Was the Trivy scanner itself broken, or only the GitHub Action?

Three things were affected. The Trivy binary release v0.69.4, the trivy-action GitHub Action and the setup-trivy GitHub Action carried the credential-stealing code, each for a different window on March 19 and 20, 2026 (UTC). Docker Hub images v0.69.5 and v0.69.6 were affected on March 22 and 23. Aqua Security's advisory lists the exact windows and the fixed versions.

I never used Trivy. Does any of this apply to me?

The same weakness applies to any third-party action you reference by a tag or branch name, because the owner of that repository, or anyone holding its credentials, can move the tag. The Trivy case is the clearest recent example. The checks in this article work for every action in your workflows.

Does a clean scan from red.run.cloud show my CI is unaffected?

No. A scan reads what your live site shows an outsider. A build pipeline answers no public request, so a scan cannot see which actions your workflows run or what they read. Only your repository, your run history and your provider's audit log can settle that.

Is pinning to a commit SHA enough?

It stops a moved tag from changing what your workflow runs, which is the failure in this incident. It does not review the code you pinned, and it does not limit what that code can read. Pair it with a read-only token, narrow secrets and a plan to update pins on purpose.

Do I need to rotate every secret in my repository?

Rotate every secret that a job running an affected action could read, which is usually every secret available to that workflow. Aqua Security's advisory says to treat all secrets accessible to affected pipelines as exposed. Secrets in other repositories that never ran the action are lower priority, but check their run history first.

Does this affect the app that people install on their phones?

The compromise targeted build pipelines and the machines that run them. An app built on a pipeline that ran an affected action could have been built next to stolen signing or store credentials, so check those credentials. Code on the phone is a separate question that your own build logs and repository history answer.

Sources

Checked October 24, 2026. The hub for this section is newly.app/security.

  1. Trivy Supply Chain Attack advisory, CVE-2026-33634 (GHSA-69fq-xp46-6x23), Aqua Security on GitHub, March 21, 2026
  2. Detecting, investigating, and defending against the Trivy supply chain compromise, Microsoft Security Blog, March 24, 2026
  3. Security update, March 2026, LiteLLM docs
  4. GHSA-5mg7-485q-xm76, litellm 1.82.7 and 1.82.8, GitHub Advisory Database, March 25, 2026
  5. Incident report: LiteLLM and Telnyx supply chain attack, PyPI blog, April 2, 2026
  6. LiteLLM compromised on PyPI and Docker, Datadog Security Labs, October 21, 2026
  7. Security incident, October 21, 2026, LiteLLM docs
  8. Secure use reference, GitHub Docs
  9. Controlling permissions for GITHUB_TOKEN, GitHub Docs
  10. Using secrets in GitHub Actions, GitHub Docs
  11. GitHub Actions policy now supports blocking and SHA pinning actions, GitHub Changelog, August 15, 2025
  12. Trusted Publishers, PyPI docs
  13. Environment variables in EAS, Expo docs

Continue Learning