Skip to content

ci: enforce exact (pinned) dependency versions to harden supply chain#44

Open
goastler wants to merge 1 commit into
mainfrom
chore/pin-exact-dependency-versions
Open

ci: enforce exact (pinned) dependency versions to harden supply chain#44
goastler wants to merge 1 commit into
mainfrom
chore/pin-exact-dependency-versions

Conversation

@goastler

Copy link
Copy Markdown
Member

What

Adds a pinned-versions GitHub Actions workflow (runs on PRs) that fails if any dependency is not pinned to an exact version, and pins all existing floating specifiers.

The check (.github/scripts/check-pinned-versions.mjs, pure Node, no install needed) flags:

  • any dependencies / devDependencies / optionalDependencies entry using a floating range (^, ~, *, latest, >=, …)
  • any package-lock.json registry package missing an integrity hash

Why — supply-chain hardening

Floating ranges let npm install silently pull a newer, unreviewed release. That is exactly the vector behind recent npm attacks:

  • Shai-Hulud worm (Sep 2025) — self-replicating worm trojanised 500+ packages (incl. @ctrl/tinycolor, ~2.2M weekly downloads) to steal npm/cloud tokens and auto-publish.
  • chalk / debug / ansi-styles hijack (Sep 2025) — 18 packages totalling ~2.6B weekly downloads compromised via a maintainer phish to inject a crypto-wallet drainer.
  • nx (Aug 2025) — malicious postinstall harvested SSH keys, npm tokens and wallets.
  • ua-parser-js (Oct 2021) and event-stream / flatmap-stream (Nov 2018) — earlier classics of the same pattern.

Exact versions + committed lockfile + npm ci mean a malicious new release is not pulled until the version is explicitly bumped and reviewed.

peerDependencies / optionalDependencies

  • peerDependencies are exempt — they intentionally express a compatibility range against whatever the consumer installs; pinning them would wrongly constrain downstream projects. The actually-installed peer is still pinned by the lockfile.
  • optionalDependencies are enforced (e.g. fsevents pinned to its resolved version).

Safety

Existing floating specifiers were rewritten to the exact version already resolved in package-lock.json, so this changes nothing about what installs. The lockfile's recorded ranges were synced to match (no resolved-version/integrity changes) so npm ci stays in sync.

@netlify

netlify Bot commented Jun 12, 2026

Copy link
Copy Markdown

Deploy Preview for peaceful-pothos-9e62ce ready!

Name Link
🔨 Latest commit 00b93ee
🔍 Latest deploy log https://app.netlify.com/projects/peaceful-pothos-9e62ce/deploys/6a2c78eaf496a3000804cd71
😎 Deploy Preview https://deploy-preview-44--peaceful-pothos-9e62ce.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@goastler goastler force-pushed the chore/pin-exact-dependency-versions branch 2 times, most recently from 01e20f8 to 7f9ad4e Compare June 12, 2026 21:16
Add a pinned-versions GitHub workflow that runs on PRs and fails if any
dependencies/devDependencies/optionalDependencies entry in a package.json
uses a floating range (^, ~, *, latest, ...), or if package-lock.json is
missing integrity hashes for resolved registry packages. peerDependencies
are exempt as they intentionally express compatibility ranges.

Floating ranges let `npm install` silently pull a newer, unreviewed release
- the vector behind recent npm supply-chain attacks: the Shai-Hulud worm
(Sep 2025, 500+ packages), the chalk/debug maintainer-phish hijack (Sep 2025,
~2.6B weekly downloads), nx (Aug 2025), ua-parser-js (2021) and event-stream
(2018). Pinning exact versions + committed lockfile + `npm ci` blocks the
auto-pull of a malicious release until a version bump is explicitly reviewed.

Existing floating specifiers are pinned to the exact version already resolved
in package-lock.json (no change to what installs); the lockfile's recorded
ranges are synced to match so `npm ci` stays in sync.
@goastler goastler force-pushed the chore/pin-exact-dependency-versions branch from 7f9ad4e to 00b93ee Compare June 12, 2026 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant