|
| 1 | +--- |
| 2 | +title: "Our Response to the Trivy Supply Chain Attack" |
| 3 | +date: 2026-03-23 |
| 4 | +description: "How the Trivy GitHub Actions compromise affected DevRail, what we found, and what we changed." |
| 5 | +--- |
| 6 | + |
| 7 | +On March 19, 2026, attackers compromised credentials for the Aqua Security GitHub organization and force-pushed 75 of 76 version tags in the [trivy-action](https://github.com/aquasecurity/trivy-action) repository to point at malicious commits containing an infostealer. A malicious Trivy binary (v0.69.4) was also briefly published. This post covers our assessment and response. |
| 8 | + |
| 9 | +## What Happened |
| 10 | + |
| 11 | +The attackers exploited credentials that were not fully rotated after a prior incident on March 1. During a window of approximately 12 hours (March 19 ~17:43 UTC to March 20 ~05:40 UTC), every `trivy-action` tag from `0.0.1` through `0.34.0` pointed to a commit that ran a Python-based credential stealer. The payload harvested environment variables, SSH keys, cloud credentials, Kubernetes tokens, and other secrets from CI runners, then exfiltrated them to a command-and-control server. |
| 12 | + |
| 13 | +Full details are available in [Aqua Security's advisory](https://github.com/aquasecurity/trivy/discussions/10425) and [aquasecurity/trivy-action#541](https://github.com/aquasecurity/trivy-action/issues/541). |
| 14 | + |
| 15 | +## Impact on DevRail |
| 16 | + |
| 17 | +**No DevRail secrets were compromised.** |
| 18 | + |
| 19 | +Our CI workflow (`ci.yml`) referenced `aquasecurity/trivy-action@0.28.0`, which was among the hijacked tags. However, all CI runs on March 19 completed by 04:58 UTC -- approximately 13 hours before the attack window opened at ~17:43 UTC. No CI jobs ran during the compromise period. |
| 20 | + |
| 21 | +The Trivy binary inside the dev-toolchain container (v0.69.3, installed via the APT repository at `get.trivy.dev/deb`) was not affected. The malicious binary was v0.69.4, which was published only via GitHub releases and Docker Hub, not the APT channel. |
| 22 | + |
| 23 | +| Component | Our version | Status | |
| 24 | +|---|---|---| |
| 25 | +| Trivy binary in container | 0.69.3 (APT) | Not affected | |
| 26 | +| `trivy-action` in CI | `@0.28.0` (tag) | Tag was hijacked, but no runs during the window | |
| 27 | +| `setup-trivy` | Not used | N/A | |
| 28 | + |
| 29 | +## What We Changed |
| 30 | + |
| 31 | +We pinned `trivy-action` to a full commit SHA instead of a version tag: |
| 32 | + |
| 33 | +```yaml |
| 34 | +# Before (vulnerable to tag poisoning) |
| 35 | +uses: aquasecurity/trivy-action@0.28.0 |
| 36 | + |
| 37 | +# After (immune to tag poisoning) |
| 38 | +uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 |
| 39 | +``` |
| 40 | +
|
| 41 | +Version 0.35.0 was created after the first incident and was confirmed safe by Aqua Security. |
| 42 | +
|
| 43 | +This change is in [dev-toolchain PR #18](https://github.com/devrail-dev/dev-toolchain/pull/18). |
| 44 | +
|
| 45 | +## Lessons |
| 46 | +
|
| 47 | +**Pin GitHub Actions to commit SHAs, not version tags.** Git tags are mutable -- anyone with write access can force-push a tag to point at any commit. A compromised maintainer credential is enough to silently replace every version of an action with malicious code. SHA references are immutable and cannot be changed after the fact. |
| 48 | +
|
| 49 | +This applies to all third-party GitHub Actions, not just Trivy. The [GitHub documentation on security hardening](https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions) recommends the same practice. |
| 50 | +
|
| 51 | +**Install tools from package managers when possible.** The Trivy binary inside our container was installed via APT, not from GitHub releases. The APT channel was not compromised. Package manager distribution adds a layer of indirection that makes supply chain attacks harder to execute -- the attacker would need to compromise the package repository infrastructure, not just a single GitHub credential. |
| 52 | +
|
| 53 | +**Monitor your CI execution windows.** Knowing exactly when your CI jobs ran relative to a compromise window is the difference between "rotate everything" and "no action needed." We were able to confirm no exposure because our run timestamps were well outside the attack period. |
0 commit comments