DEV Community

Cover image for Pinning GitHub Actions to a tag is mass negligence and we all just watched it happen
Aditya Agarwal
Aditya Agarwal

Posted on

Pinning GitHub Actions to a tag is mass negligence and we all just watched it happen

Many of your CI pipelines can easily be manipulated to execute any code with a single force-push. And you likely unwittingly enabled this yourself.

I certainly did.

What Actually Happened

In March 2026, LiteLLM was breached using a poisoned Trivy GitHub Action. The threat actor didn't publish a new, obviously-malicious action under a typo-squatted name. They force-pushed malicious code to existing release tags that teams were already using.

In other words, the @v1 or @v2 that you pinned to? It's mutable. Anyone with write access to that repo can point it at completely different code whenever they want.

Why Tag Pinning Is a Trust-Me Handshake

Here's what most workflows you'll see in the wild look like:

- uses: some-org/some-action@v1
Enter fullscreen mode Exit fullscreen mode

See that @v1? It feels nice and pinned, right? Looks like a version. Your brain pattern-matches it to npm semver or Docker tags and moves on.

However, it's just a Git tag. Git tags are not immutable. A maintainer — or an attacker who has compromised a maintainer — could delete and recreate that tag pointing at any commit they want. Your next workflow run pulls the new code silently.

No diff. No notification. No PR review. Nothing.

→ Tag pinning gives you the illusion of reproducibility without actual reproducibility.
→ You're trusting every maintainer of every action, forever, with access to your CI secrets.
→ A single compromised token upstream means your GITHUB_TOKEN, cloud credentials, and deploy keys are exposed.

Every startup I've worked at has pinned to tags. Every template repo on GitHub has pinned to tags. Every "getting started" tutorial ever has told you to pin to a tag. We all collectively normalized this. 🤷

The Fix Is Boring and That's the Problem

In fact, GitHub themselves recommend pinning actions to full commit SHAs:

- uses: some-org/some-action@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
Enter fullscreen mode Exit fullscreen mode

A commit SHA is immutable. You can't force-push over it. If someone pushes malicious code, it gets a new SHA, and your workflow will keep running the old, safe commit.

→ SHA pinning is the only pinning that actually pins anything.
→ Tools like Dependabot and Renovate can auto-update SHA pins with readable diffs.
→ You can add a comment with the tag for readability: @a1b2c3... # v2.1.0

Yes, it's ugly. Yes, it's annoying. But "annoying" beats "compromised" every single time.

This Is a Supply Chain Problem We Keep Ignoring

We dedicated years to studying left-pad, event-stream, and colors.js. We created lockfiles, SBOMs, and signed packages. Then we turned around and gave our CI pipelines — the things with write access to production — zero supply chain discipline.

Your CI runner has secrets that your application code doesn't. Cloud provider keys. Package registry tokens. Deploy credentials. For most organizations, it's the single highest-value target, and we're protecting it with vibes. 🔓

The LiteLLM incident wasn't sophisticated. It was embarrassingly simple, and that's what makes it terrifying.

What I Changed

After reading about this, I spent an afternoon auditing our workflows at the startup where I work. Every single third-party action was pinned to a tag. Every one.

I replaced all of those with SHA pins + tag comments, and added Renovate to automatically open PRs with the new SHAs. The whole thing took maybe two hours. Two hours to close a door that was wide open to any upstream compromise.

If you haven't done this yet, maybe today's the day.


Here's my question for you: Do you pin to SHAs already, and if not, what's actually stopping you? Is it tooling, awareness, or just inertia?

Top comments (0)