Skip to content
OTFotf
All posts

Can We Still Trust Vulnerability Scanners After Trivy Attack?

D
DaveAuthor
6 min read
Can We Still Trust Vulnerability Scanners After Trivy Attack?

Trivy is the scanner that runs before your code gets near production. That ubiquity is exactly what made it a target. On 17 July 2026, TechRound reported that security researchers — including Microsoft — had caught a sophisticated supply-chain attack in which the attackers compromised Trivy's distribution channels, poisoned its GitHub Actions tags, and slipped malicious dependencies into the trusted release paths developers pull from every day.

This is not a hit piece on Trivy. It is the cleanest possible case for treating your scanner like every other binary you ship: pin it, sign it, audit it. The same trust you put in your CI/CD runner should extend to the binaries that runner executes — and when it doesn't, the scanner stops being a defence and starts being the initial-access vector.

What actually happened to Trivy

The attackers didn't try to break into anyone's pipeline directly. They went upstream and corrupted the distribution itself. Researchers traced the campaign to Trivy's GitHub Actions workflow tags and to Docker images and repository-level artifacts tied to the same release paths. CI/CD systems that pulled an affected version ran the payload automatically — no human review, no second click, because that is how pipelines are designed to work. The attack landed with the right brand name, in the right place, on the right command.

Once executed, the payload did exactly what a credential harvester is written to do. It went hunting for API tokens, cloud provider credentials, and deployment keys sitting in the CI/CD run. Anything reachable from that environment was in scope — source repositories, container registries, third-party API keys. An attacker who walks out of a compromised pipeline walks out with a full set of follow-on access. The blast radius is not the one application that just got scanned. It is every downstream system the pipeline can talk to.

Why a scanner becomes an attack surface

The blind spot is conceptual. A scanner is treated as part of the security perimeter — a thing you trust by definition — rather than as another binary that needs to be verified. That assumption is the vulnerability. Attackers didn't have to defeat your defences; they just had to stand inside them by riding the trust developers extend to a familiar tool.

This is the security-through-familiarity fallacy: the more a tool is installed, the less it gets checked. The same logic would say your bash binary needs no audit because you run it on every machine. It is a category error, and it is the exact category error attackers now exploit. The trust relationship between developer and scanner is a channel, and channels are targetable.

Same component. Web and mobile. One codebase.

The free, open-source SDK gives you components that work the same on web and mobile — one codebase. github.com/otf-kit/sdk

Get the free SDK

Pin, verify, and stop trusting tags

The fix is unglamorous and mechanical. Pull-by-tag is convenient; pull-by-digest with a checksum is verifiable. Here is what the minimum looks like in practice.

Pin to an immutable digest, not a moving tag:

# In CI, never run "aquasec/trivy:latest"
docker run --rm \
  aquasec/trivy@sha256:REPLACE_WITH_PINNED_DIGEST \
  image --exit-code 1 --severity HIGH,CRITICAL my-image:tag

Record the digest in your repository so the next person to update Trivy does so deliberately:

// renovate.json — pin the Trivy image by digest, not by tag
{
  "packageRules": [
    {
      "matchDatasources": ["docker"],
      "matchPackageNames": ["aquasec/trivy"],
      "pinDigests": true
    }
  ]
}

Verify the binary you download from the GitHub release page the same way you'd verify a Go toolchain:

# Fetch the official checksum file
curl -fsSL  \
  -o trivy_checksums.txt
# Verify the binary you downloaded
sha256sum -c trivy_checksums.txt --ignore-missing

And in GitHub Actions, pin the action itself by SHA — tags can move, commit SHAs cannot:

- uses: aquasecurity/trivy-action@<FULL_COMMIT_SHA>  # not @main, not @v0.x
  with:
    imageRef: my-image:tag
    severity: HIGH,CRITICAL
    exitCode: "1"

If your scanner runs in your pipeline, the scan step is exactly the step an attacker wants to compromise. Treat it the same way you treat any other privileged step.

pull-by-tag vs pull-by-digest + checksum

Harden the pipeline around the scanner

Pinning fixes the binary. The rest of the pipeline still needs hardening, because the scanner is downstream of several things that are easier to compromise than the scanner itself.

  • Least privilege for the CI identity. The OIDC token your runner uses should only be able to push to the one registry it is supposed to push to, and read the one repo it is supposed to read. If the Trivy step gets hijacked tomorrow, it should not also have the keys to your cloud account.
  • Scope secrets to the step that needs them. GitHub Actions supports per-step env: blocks; GitLab supports per-job variables:. A secrets.CLOUD_ROLE_ARN that is only mounted for the deploy step cannot be read by the scan step. This is the single highest-use CI/CD change you can make this quarter.
  • Egress filtering. A scanner should not need to talk to arbitrary hosts at runtime. Lock its outbound network to the registry it pulls images from and the vulnerability database it updates from. A credential harvester that cannot phone home is much less useful.
  • Isolated runners. Self-hosted runners should be ephemeral — one job, one VM, then destroyed. A long-lived runner that has been running for months is the easiest persistence target in your org.
  • Verify your dependency graph, not just your container. The campaign also poisoned repository-level artifacts tied to the same release paths. package-lock.json, go.sum, Cargo.lock — these are the canonical record of what your build actually used. If they don't exist or are not consulted, your build is reading from a wall of moving tags.

blast radius of a compromised CI/CD identity — one harvest token reaches source repos, con

The durable layer underneath the churn

Scanners come and go. Trivy today, something else tomorrow. The shape of the attack doesn't change: trust the binary, exploit the trust. What doesn't change is the plumbing — the pinned image, the signed checksum, the scoped secret, the ephemeral runner, the lockfile consulted on every build. That plumbing is worth more than any single scanner, because it survives the next CVE, the next release, the next "should we switch tools" thread.

This is the part of the build that pays you back across model churn, framework churn, and scanner churn. It is also the part that breaks the moment one developer updates a tag without thinking. A durable setup makes the safe path the default path — pinned by default, signed by default, scoped by default — so that "I just bumped Trivy" stops being a security event and starts being a routine PR. The point isn't which scanner you run. The point is that the build is reproducible from a template, and the template is reviewed, and the review is the audit trail.

What to do this week

  1. List every place your pipeline pulls a scanner image or action. Convert every tag to a digest or commit SHA before the end of the day.
  2. Audit the secrets your CI identity can read. Anything not used by the current job should be unmounted, not just unprinted.
  3. Add sha256sum -c (or cosign verification, if you have a registry that supports it) to your release-pull script. Reject the build if it fails.
  4. Write a one-page incident note for "what we'd do if our scanner were compromised tomorrow." You will not need it this month. You will be grateful for it the day you do.

A scanner you can verify is still one of the best tools in your pipeline. A scanner you trust blindly is a credential harvester with your brand on it. The difference is six lines of YAML and the discipline to keep them in place.

securitysupply-chainci-cd
OTF SDK + Kits

Buy once, own the code. Ship with the agent you already use.

  • Free, open-source SDK — same component, web and mobile
  • Paid kits include AI configs + 40+ tested prompts — your agent reads the whole project
  • $99/kit or $149 for everything. No subscription, no sandbox limit.