The Pin Bar 2026

2026-04-28 - depmedic - 20 popular OSS repos, 1,461 uses: references, what % pin to a SHA

Pinning third-party Actions to a 40-character commit SHA - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 rather than uses: actions/checkout@v4 - is the single most-recommended hardening in GitHub's own security guide. It's why pinned-action-sha is a warn-level rule in ci-doctor.

How often is the recommendation actually followed in famous OSS? We have the data lying around because the depmedic leaderboard already pulls every workflow from 20 popular repos every day. Here are the numbers from the latest snapshot.

Headline numbers

Repos audited20
Total uses: references1,461
Pinned to a 40-char SHA868 (59.4%)
Pinned to a tag (@v4, @main...)592 (40.5%)
Unpinned (no @)1
Repos at 100%6 (deno, axios, express, jest, webpack, rollup)
Repos at 0%4 (parcel, preact, react-router, got)

Per-repo board

RepoPin %PinnedTotalBar
denoland/deno100%368368
axios/axios100%6060
expressjs/express100%2222
jestjs/jest100%3535
webpack/webpack100%4848
rollup/rollup100%5050
prettier/prettier98.0%5051
microsoft/TypeScript93.2%6873
storybookjs/storybook74.3%81109
vitejs/vite37.5%1540
vercel/next.js34.0%48141
sveltejs/svelte23.1%939
tannerlinsley/react-query20.0%420
eslint/eslint6.5%346
facebook/react3.3%6180
vuejs/core2.4%142
sindresorhus/got0%02
remix-run/react-router0%052
preactjs/preact0%032
parcel-bundler/parcel0%051

What the headline number means

59.4% sounds bad on its face. It's not as bad as it looks - and it's not as good either.

Why pinning matters in 30 seconds

When you write uses: tj-actions/changed-files@v45, GitHub resolves v45 to whatever commit the maintainer most recently tagged that way. Tags are mutable. If the maintainer's npm or PyPI account is compromised - or, say, if the action gets a malicious push the way tj-actions/changed-files did in March 2025 - your CI immediately runs the attacker's payload. Workflows then have access to GITHUB_TOKEN, your secrets.*, and on private runners often the runner's filesystem and AWS metadata service.

Pinning to a 40-character SHA fixes this. The SHA is content-addressed, so it cannot be moved out from under you. You give up automatic updates - which is why configuring Dependabot for github-actions is the paired move.

Fix it in your repo, in two minutes

$ npx pin-actions             # rewrites every uses: in .github/workflows to a SHA
$ npx pin-actions --check     # CI gate: exit 1 if anything is unpinned

pin-actions is the depmedic-built free CLI that does the rewrite, comment-preserving, in place. Pair it with the github-actions entry in .github/dependabot.yml and you get the security of pinning without the maintenance tax.

Verify on your own repo

No install needed:

Score your own repo on the leaderboard

The depmedic leaderboard ranks 20+ OSS repos by CI hygiene every day. Want yours added? Email depmedicdev@gmail.com with the repo URL. No charge.

See the leaderboard Read the rule

Methodology

Source: the depmedic leaderboard's nightly scrape of all .github/workflows/*.yml files in 20 popular OSS repos. Counting rule: every uses: owner/repo@ref reference (including reusable workflows). ./ local references and docker:// step refs are excluded. A reference counts as "pinned" iff ref matches /^[0-9a-f]{40}$/i. No deduplication: a single action used in five jobs counts five times.

Snapshot date: 2026-04-28. Data + script: tools/analyze-pin-bar.mjs.