<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pico</title>
    <description>The latest articles on DEV Community by Pico (@piiiico).</description>
    <link>https://dev.to/piiiico</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3845861%2F9b3524f7-dcbf-476f-a8ec-fe2f6010c4db.png</url>
      <title>DEV Community: Pico</title>
      <link>https://dev.to/piiiico</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piiiico"/>
    <language>en</language>
    <item>
      <title>PostCSS Adopted Staged Publishing. 685M Weekly Downloads Now Gated.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 27 Jun 2026 14:54:51 +0000</pubDate>
      <link>https://dev.to/piiiico/postcss-adopted-staged-publishing-685m-weekly-downloads-now-gated-8cj</link>
      <guid>https://dev.to/piiiico/postcss-adopted-staged-publishing-685m-weekly-downloads-now-gated-8cj</guid>
      <description>&lt;p&gt;On June 18, 2026, I filed &lt;a href="https://github.com/postcss/postcss/issues/2096" rel="noopener noreferrer"&gt;postcss/postcss#2096&lt;/a&gt; about OIDC provenance for PostCSS. The &lt;code&gt;ai&lt;/code&gt; npm account — one person, Andrey Sitnik — publishes PostCSS, nanoid, Autoprefixer, browserslist, and caniuse-lite. Combined: over 900 million weekly downloads through a single publish credential.&lt;/p&gt;

&lt;p&gt;Andrey's first reply was not agreement. It was a correction.&lt;/p&gt;

&lt;h2&gt;
  
  
  "CI-as-publisher increased the attack risks"
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://github.com/postcss/postcss/issues/2096#issuecomment-2881773698" rel="noopener noreferrer"&gt;his comment&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Provenance wouldn't save from all of that supply chain attack. The old CI-only based provenance was also a reason of TanStack Shai-Hulud attack.&lt;/p&gt;

&lt;p&gt;CI-as-publisher &lt;em&gt;increased&lt;/em&gt; the attack risks compared to 2FA manual publishing. TanStack was attacked only because they publish by CI and it was a token on CI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He is right. TanStack's May 2026 compromise came through GitHub Actions cache poisoning. The attacker got an OIDC token from the CI runner and used it to publish. The provenance attestation was valid — the package was built by TanStack's CI pipeline. The CI pipeline was just also running the attacker's code.&lt;/p&gt;

&lt;p&gt;Red Hat's June 1 compromise proved the same pattern. Thirty-two packages published through a compromised GitHub account's CI pipeline. All 32 had valid SLSA provenance attestations.&lt;/p&gt;

&lt;p&gt;Andrey's argument: if you publish manually with hardware-bound 2FA (passkey, YubiKey), the attacker needs physical access to your device. If you publish through CI, the attacker needs a GitHub token — a much larger attack surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  The resolution: Staged Publishing
&lt;/h2&gt;

&lt;p&gt;npm's &lt;a href="https://docs.npmjs.com/cli/commands/npm-stage" rel="noopener noreferrer"&gt;Staged Publishing&lt;/a&gt; splits the problem: CI builds and stages. A human approves before &lt;code&gt;latest&lt;/code&gt; moves. A stolen CI token stages a malicious version but never promotes it.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://github.com/postcss/postcss/issues/2096#issuecomment-2884022703" rel="noopener noreferrer"&gt;Andrey's follow-up&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I already moved &lt;code&gt;nanoid&lt;/code&gt; and &lt;code&gt;nanospy&lt;/code&gt; to the new process, we can test them.&lt;/p&gt;

&lt;p&gt;PostCSS will be done in a week or two (too many other open source projects) 😅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The diff
&lt;/h2&gt;

&lt;p&gt;nanoid's &lt;a href="https://github.com/ai/nanoid/blob/main/.github/workflows/release.yml" rel="noopener noreferrer"&gt;release.yml&lt;/a&gt;, updated June 18:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish npm package&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm stage publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PostCSS followed through
&lt;/h2&gt;

&lt;p&gt;Andrey said "a week or two." It took nine days. As of June 27, four of the seven packages under the &lt;code&gt;ai&lt;/code&gt; npm account have Staged Publishing enabled:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly downloads&lt;/th&gt;
&lt;th&gt;Staged Publishing&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;postcss&lt;/td&gt;
&lt;td&gt;251M&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nanoid&lt;/td&gt;
&lt;td&gt;207M&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;browserslist&lt;/td&gt;
&lt;td&gt;166M&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;autoprefixer&lt;/td&gt;
&lt;td&gt;61M&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;caniuse-lite&lt;/td&gt;
&lt;td&gt;171M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;postcss-nested&lt;/td&gt;
&lt;td&gt;54M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;postcss-js&lt;/td&gt;
&lt;td&gt;53M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's 685 million weekly downloads now behind a human approval gate. One GitHub issue, nine days, no drama.&lt;/p&gt;

&lt;p&gt;Three more packages remain. When caniuse-lite, postcss-nested, and postcss-js adopt, the entire PostCSS ecosystem — 963 million weekly downloads — will be gated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scans your lockfile. Flags single-publisher packages at scale. Shows provenance, Staged Publishing, and dormant access status. When nanoid's score went from 90 to 92 after adopting Staged Publishing, the CLI picked it up automatically.&lt;/p&gt;

&lt;p&gt;The full PostCSS ecosystem audit data comes from &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt;, which scores packages on behavioral signals rather than declared metadata.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>vitebot Publishes 140 Million npm Downloads Per Week. The Account Has Zero Public Repos.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 27 Jun 2026 10:08:20 +0000</pubDate>
      <link>https://dev.to/piiiico/vitebot-publishes-140-million-npm-downloads-per-week-the-account-has-zero-public-repos-1k11</link>
      <guid>https://dev.to/piiiico/vitebot-publishes-140-million-npm-downloads-per-week-the-account-has-zero-public-repos-1k11</guid>
      <description>&lt;p&gt;Vite is the build tool behind most of the modern JavaScript ecosystem. React, Vue, Svelte, Astro, Nuxt, SolidStart all default to it. The package gets 140 million npm installs per week. It shipped 740 versions.&lt;/p&gt;

&lt;p&gt;Every one of those versions published in the last five years came from a single npm account: &lt;code&gt;vitebot&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The publisher lifecycle
&lt;/h2&gt;

&lt;p&gt;Vite has had four npm publishers over its lifetime. Two had their access revoked: &lt;code&gt;antfu&lt;/code&gt; (53 months inactive, 22 versions) and &lt;code&gt;patak&lt;/code&gt; (32 months inactive, 72 versions). The third, &lt;code&gt;yyx990803&lt;/code&gt; (Evan You, who created Vite) published 195 versions. His last publish was October 7, 2021. That was 57 months ago. His access was never revoked.&lt;/p&gt;

&lt;p&gt;The fourth, &lt;code&gt;vitebot&lt;/code&gt;, is the sole active publisher.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly Downloads&lt;/th&gt;
&lt;th&gt;Active Publisher&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/vite" rel="noopener noreferrer"&gt;vite&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;140M&lt;/td&gt;
&lt;td&gt;vitebot&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/vitest" rel="noopener noreferrer"&gt;vitest&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;70M&lt;/td&gt;
&lt;td&gt;1 active, 2 dormant&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/@vitejs/plugin-react" rel="noopener noreferrer"&gt;@vitejs/plugin-react&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;65M&lt;/td&gt;
&lt;td&gt;vitebot&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/@vitejs/plugin-vue" rel="noopener noreferrer"&gt;@vitejs/plugin-vue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;7.3M&lt;/td&gt;
&lt;td&gt;vitebot&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/@vitejs/plugin-legacy" rel="noopener noreferrer"&gt;@vitejs/plugin-legacy&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.7M&lt;/td&gt;
&lt;td&gt;vitebot&lt;/td&gt;
&lt;td&gt;WARN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;283 million weekly downloads across the Vite ecosystem, published by one bot account with zero public GitHub repos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bot publishers are better. Until they aren't.
&lt;/h2&gt;

&lt;p&gt;Publishing from a CI bot is actually a better practice than publishing from a human account. Bot tokens live in CI secrets, not in someone's &lt;code&gt;.npmrc&lt;/code&gt; on a personal laptop. They can be scoped, rotated, and audited. The Vite team gets credit for this.&lt;/p&gt;

&lt;p&gt;The problem isn't that &lt;code&gt;vitebot&lt;/code&gt; exists. The problem is that &lt;code&gt;vitebot&lt;/code&gt; is the &lt;em&gt;only&lt;/em&gt; gate. If the CI pipeline is compromised by a GitHub Actions workflow injection, a stolen repo secret, or a forked workflow with a poisoned build step, one push reaches 140 million weekly installs.&lt;/p&gt;

&lt;p&gt;This is what happened to Red Hat in June 2026. A compromised GitHub account pushed code to @redhat-cloud-services packages. The CI pipeline published the malware. The packages had valid SLSA provenance. Provenance just signed the attack.&lt;/p&gt;

&lt;p&gt;Vite publishes with OIDC provenance too. That's a plus. But provenance proves the build came from a pipeline. It does not prove a human reviewed the release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evan You's dormant access
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;yyx990803&lt;/code&gt; published 195 versions of Vite. His last publish was October 2021, 57 months ago. He still has publish access to both &lt;code&gt;vite&lt;/code&gt; and &lt;code&gt;@vitejs/plugin-react&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Vite team already revoked access for &lt;code&gt;antfu&lt;/code&gt; and &lt;code&gt;patak&lt;/code&gt;. Whoever did that cleanup missed the creator's own account. Revoking one dormant account while leaving another is the exact pattern we found in &lt;a href="https://getcommit.dev/blog/dormant-publishers-active-access/" rel="noopener noreferrer"&gt;debug, ws, and cliui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One &lt;code&gt;npm owner rm yyx990803 vite&lt;/code&gt; closes this gap in two seconds. Evan You can be re-added if he ever needs to publish an emergency patch directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing gate: staged publishing
&lt;/h2&gt;

&lt;p&gt;npm's Staged Publishing feature adds a waiting period between &lt;code&gt;npm publish&lt;/code&gt; and the version going live. During that window, any npm owner can review the tarball and cancel the release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/blog/staged-publishing-detection/" rel="noopener noreferrer"&gt;Hono adopted it&lt;/a&gt; after we flagged them as CRITICAL. PostCSS is in progress. Vite hasn't.&lt;/p&gt;

&lt;p&gt;With staged publishing enabled, a compromised &lt;code&gt;vitebot&lt;/code&gt; push would still trigger a staging period. A human on the team would see it. They'd have time to cancel before 140 million weekly installs pull the poisoned version.&lt;/p&gt;

&lt;p&gt;Without it, the path from compromised token to production is a single &lt;code&gt;npm publish&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What frameworks ship through vitebot
&lt;/h2&gt;

&lt;p&gt;Vite isn't just one package in one project. It's the build layer for the frameworks that most new projects start with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt; uses Vite for its Turbopack-compatible dev server path&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nuxt&lt;/strong&gt; bundles @vitejs/plugin-vue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SvelteKit&lt;/strong&gt; uses @sveltejs/vite-plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Astro&lt;/strong&gt; depends on Vite at its core&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SolidStart&lt;/strong&gt;, &lt;strong&gt;Remix&lt;/strong&gt;, &lt;strong&gt;Qwik&lt;/strong&gt; — all Vite-based&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single compromise reaches not just Vite users, but every framework that depends on Vite transitively. That's most of the modern frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you're on the Vite team:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Revoke &lt;code&gt;yyx990803&lt;/code&gt;'s dormant publish access (&lt;code&gt;npm owner rm yyx990803 vite&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Enable staged publishing on &lt;code&gt;vite&lt;/code&gt; and &lt;code&gt;@vitejs/plugin-react&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Consider adding a second active human publisher for emergency review&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;If you depend on Vite:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pin versions in your lockfile and review lockfile diffs in PRs&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npx proof-of-commitment --file package-lock.json&lt;/code&gt; to check your full dependency tree&lt;/li&gt;
&lt;li&gt;Add a CI gate: &lt;code&gt;npx proof-of-commitment --fail-on=critical&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How we found this
&lt;/h2&gt;

&lt;p&gt;Commit scores every npm package on behavioral signals — publisher depth, dormant access, release patterns, and provenance status. The publisher lifecycle analysis was added in v1.35.0 and flagged &lt;code&gt;vitebot&lt;/code&gt; as the sole active publisher across the Vite ecosystem.&lt;/p&gt;

&lt;p&gt;Data pulled June 27, 2026 from the npm registry and Commit API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment vite vitest @vitejs/plugin-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns the same publisher-depth verdict in 30 seconds, zero install.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://getcommit.dev/blog/vite-bot-140m-downloads/" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment: signals harder to fake than stars, READMEs, or download counts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>supplychain</category>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>debug Has 653M Weekly Downloads. One Publisher Hasn't Touched It in 8 Years. They Can Still Push a Release.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Mon, 22 Jun 2026 08:58:18 +0000</pubDate>
      <link>https://dev.to/piiiico/debug-has-653m-weekly-downloads-one-publisher-hasnt-touched-it-in-8-years-they-can-still-push-a-4h07</link>
      <guid>https://dev.to/piiiico/debug-has-653m-weekly-downloads-one-publisher-hasnt-touched-it-in-8-years-they-can-still-push-a-4h07</guid>
      <description>&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; checks for known vulnerabilities. It doesn't check whether someone who hasn't published in eight years can still push a release to a package your project installs every build.&lt;/p&gt;

&lt;p&gt;We scanned the publisher lifecycle of top npm packages and flagged every account that (a) has current publish scope and (b) hasn't published to that package in 12+ months.&lt;/p&gt;

&lt;p&gt;The findings cover 2.6 billion weekly downloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly Downloads&lt;/th&gt;
&lt;th&gt;Dormant Publisher&lt;/th&gt;
&lt;th&gt;Last Published&lt;/th&gt;
&lt;th&gt;Inactive&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/debug" rel="noopener noreferrer"&gt;debug&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;653M&lt;/td&gt;
&lt;td&gt;tootallnate&lt;/td&gt;
&lt;td&gt;Sep 2017&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;105 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/cliui" rel="noopener noreferrer"&gt;cliui&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;207M&lt;/td&gt;
&lt;td&gt;bcoe&lt;/td&gt;
&lt;td&gt;Aug 2020&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/has-flag" rel="noopener noreferrer"&gt;has-flag&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;296M&lt;/td&gt;
&lt;td&gt;sindresorhus&lt;/td&gt;
&lt;td&gt;Jul 2021&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;59 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/tslib" rel="noopener noreferrer"&gt;tslib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;389M&lt;/td&gt;
&lt;td&gt;typescript-bot&lt;/td&gt;
&lt;td&gt;Oct 2024&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/cross-spawn" rel="noopener noreferrer"&gt;cross-spawn&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;234M&lt;/td&gt;
&lt;td&gt;satazor&lt;/td&gt;
&lt;td&gt;Nov 2024&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/escalade" rel="noopener noreferrer"&gt;escalade&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;168M&lt;/td&gt;
&lt;td&gt;lukeed&lt;/td&gt;
&lt;td&gt;Aug 2024&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/yargs" rel="noopener noreferrer"&gt;yargs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;219M&lt;/td&gt;
&lt;td&gt;bcoe, oss-bot&lt;/td&gt;
&lt;td&gt;Apr/May 2025&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14-15 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://getcommit.dev/npm/semver" rel="noopener noreferrer"&gt;semver&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;803M&lt;/td&gt;
&lt;td&gt;npm-cli-ops&lt;/td&gt;
&lt;td&gt;May 2025&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;13 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of these accounts can run &lt;code&gt;npm publish&lt;/code&gt; right now and push code that lands in your &lt;code&gt;node_modules/&lt;/code&gt; within minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;The npm token model is straightforward: if you have publish access, you can publish. There's no "inactive" state, no timeout, no re-authentication required after years of dormancy. A token from 2017 works in 2026.&lt;/p&gt;

&lt;p&gt;That means every dormant account is a credential target. The attacker doesn't need to find a zero-day. They need to find a &lt;code&gt;.npmrc&lt;/code&gt; on an old laptop, a token in a GitHub Actions secret that was never rotated, or a phished email on an account the owner hasn't checked in years.&lt;/p&gt;

&lt;p&gt;This is exactly how the &lt;a href="https://getcommit.dev/blog/axios-attack-prediction/" rel="noopener noreferrer"&gt;axios attack&lt;/a&gt; worked in March 2026. One stolen npm token. One push. 113 million installs per week compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  debug: the 105-month case
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;debug&lt;/code&gt; has 4 historical publishers. Two had their access revoked: &lt;code&gt;tjholowaychuk&lt;/code&gt; (TJ Holowaychuk, the original author) at 146 months inactive, and &lt;code&gt;thebigredgeek&lt;/code&gt; at 109 months.&lt;/p&gt;

&lt;p&gt;The third, &lt;code&gt;tootallnate&lt;/code&gt; (Nathan Rajlich), published 19 versions between 2014 and 2017. His last debug publish was September 2017. His access was never revoked.&lt;/p&gt;

&lt;p&gt;The active maintainer, &lt;code&gt;qix-&lt;/code&gt; (Josh Junon), published most recently. But &lt;code&gt;tootallnate&lt;/code&gt;'s account has had publish access to 653 million weekly downloads for eight years without using it.&lt;/p&gt;

&lt;p&gt;Someone cleaned up &lt;code&gt;tjholowaychuk&lt;/code&gt; and &lt;code&gt;thebigredgeek&lt;/code&gt;. They missed &lt;code&gt;tootallnate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you maintain a package:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Audit who has publish access: &lt;code&gt;npm access ls-collaborators &amp;lt;package&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Revoke access for anyone who hasn't published in 12+ months&lt;/li&gt;
&lt;li&gt;Enable &lt;a href="https://docs.npmjs.com/generating-provenance-statements#staged-publishing" rel="noopener noreferrer"&gt;npm Staged Publishing&lt;/a&gt; — it adds a review step before versions go live&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;If you depend on these packages:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pin versions in your lockfile and review lockfile diffs in PRs&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npx proof-of-commitment --file package-lock.json&lt;/code&gt; to check your full tree for dormant publisher risk&lt;/li&gt;
&lt;li&gt;Add a CI gate: &lt;code&gt;npx proof-of-commitment --fail-on=critical&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How we found this
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; tracks publisher lifecycle for every scored package: total historical publishers, who's currently active, who has access but hasn't published, and who was revoked. The dormant-with-access flag was added in v1.35.0.&lt;/p&gt;

&lt;p&gt;Scan any package: &lt;code&gt;npx proof-of-commitment debug cross-spawn yargs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or check the &lt;a href="https://getcommit.dev/audit/?packages=debug,cross-spawn,cliui,has-flag,tslib,escalade,yargs,semver" rel="noopener noreferrer"&gt;full reports&lt;/a&gt; for all packages in this article.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>OIDC Provenance Didn't Save TanStack or Red Hat. npm Staged Publishing Is the Missing Gate.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Fri, 19 Jun 2026 14:39:01 +0000</pubDate>
      <link>https://dev.to/piiiico/oidc-provenance-didnt-save-tanstack-or-red-hat-npm-staged-publishing-is-the-missing-gate-4c5</link>
      <guid>https://dev.to/piiiico/oidc-provenance-didnt-save-tanstack-or-red-hat-npm-staged-publishing-is-the-missing-gate-4c5</guid>
      <description>&lt;p&gt;Two major supply chain attacks in six weeks. Both targeted packages with OIDC provenance enabled. Both succeeded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TanStack (May 11, 2026):&lt;/strong&gt; 42 packages, 84 malicious versions in 6 minutes. Attacker exploited GitHub Actions &lt;code&gt;pull_request_target&lt;/code&gt; + cache poisoning + OIDC token extraction from runner memory. 16.8M weekly downloads on @tanstack/react-router alone. All published versions had valid SLSA attestations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red Hat @redhat-cloud-services (June 1, 2026):&lt;/strong&gt; 32 packages republished with credential-stealing malware. Attacker compromised a GitHub account, pushed orphan commits, triggered the existing CI pipeline. The pipeline built the malware, published it to npm using its own OIDC tokens, and generated valid SLSA provenance. Provenance proved "this was built by Red Hat's CI" — which was true. The CI just happened to be building malware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provenance answers the wrong question
&lt;/h2&gt;

&lt;p&gt;OIDC provenance answers: "Was this built by the expected pipeline?"&lt;/p&gt;

&lt;p&gt;When the pipeline is compromised, the answer is yes. The attestation is valid. The malware is signed.&lt;/p&gt;

&lt;p&gt;This is the gap. Provenance proves &lt;em&gt;where&lt;/em&gt; a build came from. It doesn't prove the CI pipeline wasn't tampered with.&lt;/p&gt;

&lt;h2&gt;
  
  
  npm Staged Publishing closes it
&lt;/h2&gt;

&lt;p&gt;npm Staged Publishing (GA May 2026) adds a human approval gate between CI publishing a version and that version becoming the default &lt;code&gt;npm install&lt;/code&gt; target.&lt;/p&gt;

&lt;p&gt;Without Staged Publishing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CI runs → npm publish → version is live immediately
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Staged Publishing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CI runs → npm stage → version sits in holding → human 2FA approval → version goes live
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both the TanStack and Red Hat scenarios, malicious versions would have sat in a staging area. No silent pushes to &lt;code&gt;latest&lt;/code&gt;. A human would need to review and approve each one.&lt;/p&gt;

&lt;p&gt;PostCSS maintainer Andrey Sitnik made this point directly in &lt;a href="https://github.com/postcss/postcss/issues/2096" rel="noopener noreferrer"&gt;postcss/postcss#2096&lt;/a&gt;: "CI-as-publisher increased the attack risks compared to 2FA manual publishing." He was right — and the incidents proved it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection
&lt;/h2&gt;

&lt;p&gt;npm doesn't surface whether a package uses Staged Publishing. Registry metadata doesn't include it unless a version is actively staged. CI workflow files might reference &lt;code&gt;npm stage&lt;/code&gt; commands, but nobody checks those at dependency-install time.&lt;/p&gt;

&lt;p&gt;We added Staged Publishing detection to &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; this week. Two-tier detection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;dist-tags check&lt;/strong&gt; — if a &lt;code&gt;stage&lt;/code&gt; dist-tag exists in the registry, the package is actively using staged publishing (zero extra API calls — it's already in the registry response)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions workflow scan&lt;/strong&gt; — looks for &lt;code&gt;npm stage&lt;/code&gt;, &lt;code&gt;@npm/staged-publish&lt;/code&gt;, or &lt;code&gt;staged-publish&lt;/code&gt; patterns in the package's CI configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result shows up in &lt;code&gt;scoreBreakdown.stagedPublishing&lt;/code&gt; on the API response and in the CLI output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Update: First adopter detected (June 19, 2026)
&lt;/h2&gt;

&lt;p&gt;A few hours after publishing this post, Andrey Sitnik confirmed he had moved &lt;a href="https://www.npmjs.com/package/nanoid" rel="noopener noreferrer"&gt;&lt;code&gt;nanoid&lt;/code&gt;&lt;/a&gt; (208M weekly downloads) and &lt;a href="https://www.npmjs.com/package/nanospy" rel="noopener noreferrer"&gt;&lt;code&gt;nanospy&lt;/code&gt;&lt;/a&gt; to Staged Publishing. He left a comment on the PostCSS issue inviting verification: &lt;a href="https://github.com/postcss/postcss/issues/2096#issuecomment-4752622183" rel="noopener noreferrer"&gt;"I already moved &lt;code&gt;nanoid&lt;/code&gt; and &lt;code&gt;nanospy&lt;/code&gt; to the new process, we can test them."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit picked up both within the registry cache window. Live JSON:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://poc-backend.amdal-dev.workers.dev/api/score/npm/nanoid" rel="noopener noreferrer"&gt;nanoid&lt;/a&gt;: &lt;code&gt;hasStagedPublishing: true&lt;/code&gt;, score 92/100, &lt;code&gt;stagedPublishing: 2/2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://poc-backend.amdal-dev.workers.dev/api/score/npm/nanospy" rel="noopener noreferrer"&gt;nanospy&lt;/a&gt;: &lt;code&gt;hasStagedPublishing: true&lt;/code&gt;, score 55/100, &lt;code&gt;stagedPublishing: 2/2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trigger was the &lt;code&gt;npm stage publish&lt;/code&gt; step in &lt;a href="https://github.com/ai/nanoid/blob/main/.github/workflows/release.yml" rel="noopener noreferrer"&gt;nanoid's release.yml&lt;/a&gt;. PostCSS itself still reads &lt;code&gt;false&lt;/code&gt;. That one's coming in a week or two. When Sitnik flips it, the score updates automatically.&lt;/p&gt;

&lt;p&gt;That's the test: can scoring track the new gate as maintainers actually adopt it? On the first real-world case, yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second adopter, no announcement:&lt;/strong&gt; sweeping the top of the npm tree the same afternoon turned up &lt;a href="https://www.npmjs.com/package/preact" rel="noopener noreferrer"&gt;preact&lt;/a&gt; (23M weekly downloads). No press release, no thread. Line 118 of &lt;a href="https://github.com/preactjs/preact/blob/main/.github/workflows/release.yml" rel="noopener noreferrer"&gt;preact's release.yml&lt;/a&gt; — &lt;code&gt;npm stage publish preact.tgz --provenance --access public&lt;/code&gt; — does the work. Provenance and staged publishing shipped together. Live JSON: &lt;a href="https://poc-backend.amdal-dev.workers.dev/api/score/npm/preact" rel="noopener noreferrer"&gt;preact&lt;/a&gt; returns &lt;code&gt;hasStagedPublishing: true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two signals, two adopters in the same week. One announced, one didn't. Detection picked up both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adoption accelerating: Hono adopted in 33 hours
&lt;/h2&gt;

&lt;p&gt;Two days after detection shipped, Yusuke Wada (creator of &lt;a href="https://www.npmjs.com/package/hono" rel="noopener noreferrer"&gt;Hono&lt;/a&gt;, 50M weekly downloads) replied to &lt;a href="https://github.com/honojs/hono/issues/5034" rel="noopener noreferrer"&gt;honojs/hono#5034&lt;/a&gt; twelve minutes after I filed it: &lt;em&gt;"I'm considering switching to Staged Publishing just now."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/honojs/hono/pull/5035" rel="noopener noreferrer"&gt;PR #5035 — "ci: use npm Staged publishing"&lt;/a&gt; merged 33 hours later, on 2026-06-22 at 11:42 UTC. The diff is one word:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- run: npm publish --provenance --access public
&lt;/span&gt;&lt;span class="gi"&gt;+ run: npm stage publish --provenance --access public
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hono already had OIDC provenance via &lt;a href="https://github.com/honojs/hono/pull/5028" rel="noopener noreferrer"&gt;PR #5028&lt;/a&gt;. Staged publishing adds the human approval gate on top. A compromised CI token alone can't push a malicious version to &lt;code&gt;latest&lt;/code&gt; — the same model that would have closed the gap on the TanStack and Red Hat incidents.&lt;/p&gt;

&lt;p&gt;That's four high-profile maintainers (Sitnik with nanoid and nanospy, the Preact team, Wada with Hono) moving in the same direction within a week. The pattern: sole-publisher packages at massive scale are adopting the gate that makes credential-based attacks survivable, and the friction is one word in release.yml.&lt;/p&gt;

&lt;p&gt;Full case study: &lt;a href="https://getcommit.dev/blog/hono-staged-publishing-adopted/" rel="noopener noreferrer"&gt;Hono Just Adopted Staged Publishing — 50M Weekly Downloads, 33 Hours After the Issue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans your lockfile and flags packages where a single npm publisher controls &amp;gt;10M weekly downloads — the exact attack surface that's been exploited three times since March. The output now includes whether each package uses OIDC provenance, Staged Publishing, or neither.&lt;/p&gt;

&lt;p&gt;If you see CRITICAL with no provenance and no staged publishing — that package is one stolen credential away from the next incident. And the credential doesn't have to be an npm token anymore. It can be a GitHub account, a CI cache, or an OIDC token extracted from process memory.&lt;/p&gt;

&lt;p&gt;The supply chain moved past "just use provenance" in May 2026. The question now is which packages have caught up.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>One npm Account Publishes 964 Million Downloads Per Week. None Have Provenance.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Thu, 18 Jun 2026 14:35:24 +0000</pubDate>
      <link>https://dev.to/piiiico/one-npm-account-publishes-964-million-downloads-per-week-none-have-provenance-4e2k</link>
      <guid>https://dev.to/piiiico/one-npm-account-publishes-964-million-downloads-per-week-none-have-provenance-4e2k</guid>
      <description>&lt;p&gt;The npm account &lt;code&gt;ai&lt;/code&gt; publishes seven packages. Combined, they install 964 million times per week:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly downloads&lt;/th&gt;
&lt;th&gt;Publishers&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;postcss&lt;/td&gt;
&lt;td&gt;245,612,332&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nanoid&lt;/td&gt;
&lt;td&gt;206,588,788&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;caniuse-lite&lt;/td&gt;
&lt;td&gt;173,435,668&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;browserslist&lt;/td&gt;
&lt;td&gt;167,746,012&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;autoprefixer&lt;/td&gt;
&lt;td&gt;63,517,741&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;postcss-nested&lt;/td&gt;
&lt;td&gt;54,486,292&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;postcss-js&lt;/td&gt;
&lt;td&gt;52,771,544&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's 50 billion installs per year behind a single set of npm credentials. None of them have npm provenance attestations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;npm provenance uses OIDC tokens from GitHub Actions instead of long-lived npm tokens. If a package has provenance, you can verify that the published code came from a specific commit in a specific repository — not from someone's compromised laptop.&lt;/p&gt;

&lt;p&gt;Without provenance, there's no way to distinguish a legitimate release from one pushed by a stolen token. The blast radius here is nearly a billion installs per week.&lt;/p&gt;

&lt;p&gt;This isn't theoretical. axios was attacked on March 30, 2026 through a stolen npm token — same single-publisher, no-provenance pattern. LiteLLM was hit the same way a month earlier. The Shai-Hulud worm in May 2026 exploited stolen tokens to republish 637 package versions in 39 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes this different from chalk or lodash
&lt;/h2&gt;

&lt;p&gt;PostCSS is interesting because it's not just one critical package. It's an entire ecosystem of critical packages, all behind the same account. chalk is one package, one publisher, 432M downloads/week. Bad enough. But &lt;code&gt;ai&lt;/code&gt; controls seven independent packages that each cross the 10M threshold.&lt;/p&gt;

&lt;p&gt;A compromised &lt;code&gt;ai&lt;/code&gt; token doesn't just hit postcss. It hits the CSS build pipeline (postcss + autoprefixer + postcss-nested + postcss-js), the browser compatibility layer (browserslist + caniuse-lite), and one of the most popular ID generators in the ecosystem (nanoid).&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;caniuse-lite&lt;/code&gt; was flagged with a dormant publisher warning — 61 months of inactivity on the publishing account. postcss-nested hasn't had a release in over 12 months.&lt;/p&gt;

&lt;h2&gt;
  
  
  This has been fixed before
&lt;/h2&gt;

&lt;p&gt;fast-xml-parser (88M downloads/week, single publisher) had the same problem. After the community raised &lt;a href="https://github.com/NaturalIntelligence/fast-xml-parser/issues/814" rel="noopener noreferrer"&gt;the issue&lt;/a&gt;, the maintainer set up GitHub Actions OIDC publishing. Within days, version 5.9.1 shipped with SLSA provenance attestations. Then 5.9.2 added environment gates and SHA-pinned actions. The structural gap closed in under a week.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://github.com/postcss/postcss/issues/2096" rel="noopener noreferrer"&gt;filed an issue on PostCSS&lt;/a&gt; proposing the same approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The PostCSS maintainer disagrees — and he's partially right
&lt;/h2&gt;

&lt;p&gt;Andrey Sitnik (&lt;code&gt;ai&lt;/code&gt;) responded within hours. His argument: OIDC provenance from CI is itself an attack surface. TanStack was compromised precisely because they published from CI — the stolen token came from the CI system. His words: "CI-as-publisher increased the attack risks compared to 2FA manual publishing."&lt;/p&gt;

&lt;p&gt;He's right that CI-as-sole-publisher shifts the attack surface rather than eliminating it. The Shai-Hulud worm exchanged OIDC tokens for publish credentials. TanStack was hit through GitHub Actions cache poisoning. Provenance proves &lt;em&gt;where&lt;/em&gt; a build came from; it doesn't prove the CI pipeline wasn't tampered with.&lt;/p&gt;

&lt;p&gt;His proposed alternative: &lt;strong&gt;Staged Releases&lt;/strong&gt; — a newer npm feature where CI creates the release, but a human must manually approve it before it becomes the default install target. Even if an attacker compromises the CI pipeline, the malicious version sits in a holding period. No silent pushes to &lt;code&gt;latest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The honest answer is: both are better than the current state. Right now there's no provenance, no staged releases, no second factor between a stolen credential and 964 million weekly installs. Staged Releases would address the blast-radius problem directly. Provenance would at least make attacks auditable after the fact. The worst option is what we have now: nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own dependencies
&lt;/h2&gt;

&lt;p&gt;If you want to see which packages in your project have this concentration risk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it in any project directory. It auto-detects your lockfile and flags packages where a single npm publisher controls more than 10M weekly downloads. That's the exact attack surface that's been exploited three times in four months.&lt;/p&gt;

&lt;p&gt;The full PostCSS ecosystem audit data comes from &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt;, which scores packages on behavioral signals rather than declared metadata.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>323 npm Packages Compromised in 39 Minutes. The Malware Installs a Claude Code SessionStart Hook.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Mon, 15 Jun 2026 20:37:07 +0000</pubDate>
      <link>https://dev.to/piiiico/639-npm-packages-compromised-in-39-minutes-the-malware-installs-a-claude-code-sessionstart-hook-3k38</link>
      <guid>https://dev.to/piiiico/639-npm-packages-compromised-in-39-minutes-the-malware-installs-a-claude-code-sessionstart-hook-3k38</guid>
      <description>&lt;p&gt;On May 19, 2026, between 01:39 and 02:18 UTC, a single compromised npm account published 639 malicious package versions across 323 packages. The entire attack took under 40 minutes.&lt;/p&gt;

&lt;p&gt;The packages included &lt;code&gt;jest-canvas-mock&lt;/code&gt; (2.2M weekly downloads), &lt;code&gt;echarts-for-react&lt;/code&gt; (1.1M), &lt;code&gt;size-sensor&lt;/code&gt; (1.2M), &lt;code&gt;timeago.js&lt;/code&gt; (243K), and most of the &lt;code&gt;@antv&lt;/code&gt; visualization suite. Total blast radius: roughly 16 million weekly downloads.&lt;/p&gt;

&lt;p&gt;This wasn't a human typing &lt;code&gt;npm publish&lt;/code&gt; 639 times. This was a worm.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the self-propagation works
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;atool&lt;/code&gt; npm account was compromised (how is still unknown). That account had publish access to hundreds of packages. The initial payload did what you'd expect — harvested credentials from 80+ environment variables and 100+ file paths across AWS, GCP, Azure, GitHub, Kubernetes, and database systems.&lt;/p&gt;

&lt;p&gt;Then it did something different: it searched for npm tokens with the &lt;code&gt;bypass_2fa&lt;/code&gt; scope. In GitHub Actions environments, the malware exchanged OIDC tokens for per-package npm publish credentials. It then republished additional packages with itself embedded. An npm worm.&lt;/p&gt;

&lt;p&gt;Two waves hit the registry. First: ~317 versions at 01:39. Second: ~314 versions 26 minutes later at 02:05. Detection started around 02:18. By then, the packages had been live long enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The persistence mechanisms
&lt;/h2&gt;

&lt;p&gt;The exfiltrated credentials are serialized as JSON, gzip-compressed, encrypted with AES-256-GCM, and wrapped with RSA-OAEP. The exfiltration channel disguises traffic as OpenTelemetry traces.&lt;/p&gt;

&lt;p&gt;A backup channel creates public repos under the victim's GitHub account and commits encrypted credential dumps with Dune-themed naming patterns.&lt;/p&gt;

&lt;p&gt;Here's where it gets personal if you use Claude Code or VS Code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The malware installs a &lt;code&gt;SessionStart&lt;/code&gt; hook in &lt;code&gt;.claude/settings.json&lt;/code&gt;.&lt;/strong&gt; It also drops VS Code task automation in &lt;code&gt;.vscode/tasks.json&lt;/code&gt; and a background daemon that polls GitHub every 60 seconds for RSA-signed commands.&lt;/p&gt;

&lt;p&gt;And there's a dead man's switch. If the stolen GitHub token gets revoked, the malware runs &lt;code&gt;rm -rf ~/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These aren't hypothetical persistence vectors. They're documented by &lt;a href="https://www.akamai.com/blog/security-research/mini-shai-hulud-worm-returns-goes-public" rel="noopener noreferrer"&gt;Akamai&lt;/a&gt;, &lt;a href="https://labs.cloudsecurityalliance.org/research/csa-research-note-shai-hulud-ai-supply-chain-20260517-csa-st/" rel="noopener noreferrer"&gt;CSA&lt;/a&gt;, and &lt;a href="https://expel.com/blog/mini-shai-hulud-cross-ecosystem-supply-chain-worm-targeting-npm-pypi/" rel="noopener noreferrer"&gt;Expel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the packages looked like before the attack
&lt;/h2&gt;

&lt;p&gt;I scored the compromised packages using &lt;a href="https://getcommit.dev/audit?ref=devto-shai-hulud" rel="noopener noreferrer"&gt;Commit&lt;/a&gt;. The non-AntV packages tell the clearest story:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Publishers&lt;/th&gt;
&lt;th&gt;Downloads/wk&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;canvas-nest.js&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;650&lt;/td&gt;
&lt;td&gt;WARN: no release 12+ months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;timeago.js&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;243K&lt;/td&gt;
&lt;td&gt;WARN: no release 12+ months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;size-sensor&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1.2M&lt;/td&gt;
&lt;td&gt;HIGH: sole publisher + &amp;gt;1M/wk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;echarts-for-react&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1.1M&lt;/td&gt;
&lt;td&gt;HIGH: sole publisher + &amp;gt;1M/wk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jest-canvas-mock&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2.2M&lt;/td&gt;
&lt;td&gt;WARN: no release 12+ months&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three of these five had a sole npm publisher. Two are stale — no release in over a year, still pulled by millions of projects weekly. That's exactly the profile that makes account takeover both easy and high-impact.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@antv&lt;/code&gt; packages scored higher (84–89) because they have 17–18 maintainers. But that's exactly how the attack worked: &lt;code&gt;atool&lt;/code&gt; was one of those 18 maintainers. More publishers means more attack surface when any one of them can push.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect your editor
&lt;/h2&gt;

&lt;p&gt;If you use Claude Code, Cursor, or Windsurf, you can gate package installs before they run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment hook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs a pre-install check that intercepts &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;pip install&lt;/code&gt;, and &lt;code&gt;cargo add&lt;/code&gt;. CRITICAL packages (sole publisher + millions of downloads — the exact Shai-Hulud profile) are blocked before they execute. The hook writes &lt;code&gt;.claude/settings.json&lt;/code&gt;, &lt;code&gt;.cursor/hooks.json&lt;/code&gt;, and &lt;code&gt;.windsurf/hooks.json&lt;/code&gt; so the gate works regardless of which editor is driving.&lt;/p&gt;

&lt;p&gt;The irony: the same file the worm writes to for persistence (&lt;code&gt;.claude/settings.json&lt;/code&gt;) is the one you use to defend against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check
&lt;/h2&gt;

&lt;p&gt;If your &lt;code&gt;package-lock.json&lt;/code&gt; or &lt;code&gt;yarn.lock&lt;/code&gt; includes any of these packages, check which versions you installed between 01:39 and 02:18 UTC on May 19.&lt;/p&gt;

&lt;p&gt;Then check the rest of your dependency tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The packages that scored 50-72 before this attack (sole publishers, stale releases, high downloads) are the same profile that got compromised in the LiteLLM attack, the axios attack, and now this one.&lt;/p&gt;

&lt;p&gt;The pattern doesn't change. The entry point is always the same: one compromised account with publish access to a widely-installed package.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's different about this one
&lt;/h2&gt;

&lt;p&gt;Previous supply chain attacks hit one package at a time. This one propagated. It turned compromised npm tokens into more compromised packages. The window between first publish and detection is getting shorter, but the blast radius is getting wider.&lt;/p&gt;

&lt;p&gt;And the persistence mechanisms are evolving. Targeting &lt;code&gt;.claude/settings.json&lt;/code&gt; and &lt;code&gt;.vscode/tasks.json&lt;/code&gt; means the malware survives container restarts and embeds itself in developer tooling. The exact environment where you decide which packages to trust.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://getcommit.dev/audit?ref=devto-shai-hulud" rel="noopener noreferrer"&gt;Run a supply chain audit on your project&lt;/a&gt; — or &lt;a href="https://getcommit.dev/get-started?ref=devto-shai-hulud" rel="noopener noreferrer"&gt;set up monitoring&lt;/a&gt; to get alerted when a package in your tree degrades.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>IronWorm Commits as 'claude.' It Steals Your Anthropic and OpenAI Keys.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Mon, 15 Jun 2026 14:36:00 +0000</pubDate>
      <link>https://dev.to/piiiico/ironworm-commits-as-claude-it-steals-your-anthropic-and-openai-keys-2gjn</link>
      <guid>https://dev.to/piiiico/ironworm-commits-as-claude-it-steals-your-anthropic-and-openai-keys-2gjn</guid>
      <description>&lt;p&gt;On June 3, JFrog Security Research published their analysis of IronWorm — a supply chain attack that compromised 37 npm packages through the &lt;code&gt;asteroiddao&lt;/code&gt; account. A 976KB Rust ELF binary triggered by &lt;code&gt;preinstall&lt;/code&gt;. Caught early, before spreading to popular packages. But the techniques are a step change from everything that came before.&lt;/p&gt;

&lt;p&gt;Three things make IronWorm different.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. It commits as "claude"
&lt;/h2&gt;

&lt;p&gt;Every malicious commit pushed to victim repositories uses the author identity &lt;code&gt;claude@users.noreply.github.com&lt;/code&gt;. The commit messages are routine: "fix: resolve lint warnings," "test: add missing edge case," "ci: update workflow configuration."&lt;/p&gt;

&lt;p&gt;The timestamps are forged. Some are backdated 13 years. In a repo where AI-generated commits are common and legitimate, these blend in. A developer scanning git log wouldn't notice. A code reviewer seeing a commit from "claude" might assume it came from an AI coding assistant doing its job.&lt;/p&gt;

&lt;p&gt;Social engineering adapted to the AI era. The attacker isn't pretending to be a human — they're pretending to be an AI tool the team already trusts.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. It steals AI credentials specifically
&lt;/h2&gt;

&lt;p&gt;IronWorm targets 86 environment variables and 20+ credential files. Standard targets (AWS, SSH, Docker) plus a new category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI API keys&lt;/strong&gt; (&lt;code&gt;OPENAI_API_KEY&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic API keys&lt;/strong&gt; (&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude authentication files&lt;/strong&gt; (session tokens)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor authentication files&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm publish tokens&lt;/strong&gt; (including Trusted Publishing OIDC tokens)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stolen AI keys have immediate value. An OpenAI key with no spend cap runs thousands of dollars before anyone notices. An Anthropic key runs agents that escalate the attack. An npm token turns one compromised dev into a vector for every package they maintain.&lt;/p&gt;

&lt;p&gt;The dedicated Exodus wallet module injects JavaScript to capture the password and seed mnemonic at login. This isn't a generic credential scraper — custom modules per high-value target.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. It propagates through Trusted Publishing
&lt;/h2&gt;

&lt;p&gt;npm's &lt;a href="https://docs.npmjs.com/generating-provenance-statements" rel="noopener noreferrer"&gt;Trusted Publishing&lt;/a&gt; lets packages publish via GitHub Actions OIDC tokens instead of stored credentials. Designed to be more secure: no long-lived tokens to steal.&lt;/p&gt;

&lt;p&gt;IronWorm doesn't need stored credentials. It modifies GitHub Actions workflows to request OIDC tokens at runtime, then publishes trojanized versions of the victim's packages with valid provenance attestations.&lt;/p&gt;

&lt;p&gt;The result: malicious packages that pass &lt;code&gt;npm audit signatures&lt;/code&gt;. Provenance says "published through a verified CI pipeline." It doesn't say "the CI pipeline was hijacked."&lt;/p&gt;

&lt;p&gt;Same fundamental gap Miasma exploited with Red Hat's SLSA provenance the week before. Two independent attacks, one week apart, both defeating provenance through different mechanisms. &lt;strong&gt;Provenance is a chain-of-custody stamp, not a trust signal.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What behavioral scoring shows
&lt;/h2&gt;

&lt;p&gt;I ran every IronWorm package through &lt;a href="https://getcommit.dev/audit?ref=devto-ironworm" rel="noopener noreferrer"&gt;Commit's behavioral audit&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Publishers&lt;/th&gt;
&lt;th&gt;Downloads/wk&lt;/th&gt;
&lt;th&gt;Age&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;weavedb-sdk&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;53&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;~1.2k&lt;/td&gt;
&lt;td&gt;~4yr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ai3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&amp;lt;100&lt;/td&gt;
&lt;td&gt;&amp;lt;1yr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;atomic-notes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&amp;lt;100&lt;/td&gt;
&lt;td&gt;&amp;lt;1yr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cwao&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&amp;lt;100&lt;/td&gt;
&lt;td&gt;&amp;lt;1yr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zkjson&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&amp;lt;100&lt;/td&gt;
&lt;td&gt;&amp;lt;1yr&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Single publisher. Low downloads. Limited history. Every IronWorm package fits the profile behavioral scoring catches before the first install completes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The escalation timeline
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Attack&lt;/th&gt;
&lt;th&gt;What was new&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mar 5&lt;/td&gt;
&lt;td&gt;LiteLLM&lt;/td&gt;
&lt;td&gt;Single-package PyPI credential theft&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mar 30&lt;/td&gt;
&lt;td&gt;axios&lt;/td&gt;
&lt;td&gt;99M downloads/week, stolen token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May 11&lt;/td&gt;
&lt;td&gt;Shai-Hulud&lt;/td&gt;
&lt;td&gt;Self-propagating worm, 637 packages in 39 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May 22&lt;/td&gt;
&lt;td&gt;TrapDoor&lt;/td&gt;
&lt;td&gt;Cross-ecosystem + AI assistant poisoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jun 1&lt;/td&gt;
&lt;td&gt;Miasma&lt;/td&gt;
&lt;td&gt;Forged SLSA provenance on Red Hat packages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jun 3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IronWorm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rust + eBPF rootkit + AI credential theft + Trusted Publishing propagation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each attack introduces a capability the previous one didn't have. IronWorm is the first npm supply chain malware written in Rust, first to use an eBPF kernel rootkit, first to self-propagate through Trusted Publishing OIDC.&lt;/p&gt;

&lt;p&gt;And it specifically targets AI coding assistant credentials. The attack vector has come full circle — AI tools accelerate development, but their credentials are now high-value targets, and the tools themselves are being impersonated in commit history.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gate your AI assistant's installs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment hook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;pip install&lt;/code&gt;, &lt;code&gt;cargo add&lt;/code&gt;, and &lt;code&gt;go get&lt;/code&gt; runs through a behavioral check before execution. Packages with no history get blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit your current dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rotate AI credentials&lt;/strong&gt; if any IronWorm package was installed in your environment. Check for modified GitHub Actions workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't trust provenance alone.&lt;/strong&gt; Both Miasma and IronWorm demonstrate that valid provenance attestations can come from compromised pipelines. Provenance answers "where did this come from?" Behavioral scoring answers "should I trust it?" You need both.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://getcommit.dev/get-started?ref=devto-ironworm" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts. &lt;a href="https://getcommit.dev/audit?ref=devto-ironworm" rel="noopener noreferrer"&gt;Try the audit&lt;/a&gt; or add the &lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; to your AI assistant.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>supplychain</category>
      <category>ai</category>
      <category>npm</category>
    </item>
    <item>
      <title>npm audit says you're clean. It doesn't check who can push to your dependencies.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Mon, 15 Jun 2026 09:51:40 +0000</pubDate>
      <link>https://dev.to/piiiico/npm-audit-says-youre-clean-it-doesnt-check-who-can-push-to-your-dependencies-35l5</link>
      <guid>https://dev.to/piiiico/npm-audit-says-youre-clean-it-doesnt-check-who-can-push-to-your-dependencies-35l5</guid>
      <description>&lt;p&gt;Run &lt;code&gt;npm audit&lt;/code&gt; on any Node.js project and you'll get one of two things: a clean bill of health, or a list of known CVEs with suggested version bumps.&lt;/p&gt;

&lt;p&gt;What you won't get: any signal about &lt;strong&gt;who can publish&lt;/strong&gt; the packages you depend on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The blind spot
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; checks an advisory database. If nobody has reported a vulnerability, your project is "clean." But the biggest npm attacks in 2026 didn't exploit known vulnerabilities — they exploited &lt;strong&gt;publisher access&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;axios&lt;/strong&gt; (120M downloads/week) — one npm publisher. Token stolen March 30, 2026. Malicious version pushed to 97M+ dependents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;litellm&lt;/strong&gt; — one npm publisher. Supply chain attack, March 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shai-Hulud worm&lt;/strong&gt; (May 2026) — compromised a single npm account with access to 547 packages. 637 malicious versions published in 39 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three passed &lt;code&gt;npm audit&lt;/code&gt; before the attack happened. Of course they did — there was no CVE to find.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7 packages you almost certainly depend on
&lt;/h2&gt;

&lt;p&gt;I checked the publisher counts for the most-downloaded packages in the npm registry. These 7 are in nearly every Node.js project's dependency tree, usually as transitive deps (check your lockfile):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly Downloads&lt;/th&gt;
&lt;th&gt;npm Publishers&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;minimatch&lt;/td&gt;
&lt;td&gt;648M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chalk&lt;/td&gt;
&lt;td&gt;445M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;378M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cross-spawn&lt;/td&gt;
&lt;td&gt;223M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zod&lt;/td&gt;
&lt;td&gt;195M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lodash&lt;/td&gt;
&lt;td&gt;161M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;axios&lt;/td&gt;
&lt;td&gt;120M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Combined: 2.17 billion weekly downloads. All from packages where a single stolen npm token is enough to push a malicious release.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These aren't obscure packages. &lt;code&gt;minimatch&lt;/code&gt; and &lt;code&gt;glob&lt;/code&gt; are in every project that uses file matching — which includes most build tools. &lt;code&gt;chalk&lt;/code&gt; is in everything that colors terminal output. &lt;code&gt;cross-spawn&lt;/code&gt; is in anything that spawns a child process. You didn't install them — your dependencies did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publisher ≠ contributor
&lt;/h2&gt;

&lt;p&gt;A common objection: "But chalk has hundreds of GitHub contributors!"&lt;/p&gt;

&lt;p&gt;True, and it doesn't matter. &lt;strong&gt;GitHub contributors can't publish to npm.&lt;/strong&gt; Only npm publishers can. And chalk has one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;zod&lt;/code&gt; is the same — 30+ GitHub contributors, 1 npm publisher. If that one person's npm token is phished, their 2FA is compromised, or their account is hijacked, nobody else can push a fix. The 30 contributors can open a PR. They can't publish.&lt;/p&gt;

&lt;p&gt;This is the distinction &lt;code&gt;npm audit&lt;/code&gt; doesn't make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own project (takes 5 seconds)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it in any project directory. It auto-detects your lockfile (&lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;) and scores every dependency by publisher concentration, release consistency, and age.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx proof-of-commitment
&lt;span class="go"&gt;Scoring 147 packages from package-lock.json... done in 4.2s

⚠  12 CRITICAL packages found.
&lt;/span&gt;&lt;span class="gp"&gt;   CRITICAL = sole npm publisher + &amp;gt;&lt;/span&gt;10M weekly downloads
&lt;span class="go"&gt;
Package      Risk          Score   Publishers   Downloads      Age
chalk        🔴 CRITICAL   75      1            445M/wk        14.6y
minimatch    🔴 CRITICAL   78      1            648M/wk        14.9y
glob         🔴 CRITICAL   80      1            378M/wk        14.2y
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or audit specific packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment axios zod chalk lodash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or scan a lockfile and get JSON for tooling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.criticalCount'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add it to CI (one line)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/supply-chain.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Supply Chain&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx -y proof-of-commitment --fail-on=critical&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails the build if any dependency has CRITICAL publisher concentration. Not a CVE — a structural risk.&lt;/p&gt;

&lt;p&gt;For PR comments and step summaries, there's a dedicated &lt;a href="https://github.com/piiiico/commit-action" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;piiiico/commit-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fail-on-critical&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;comment-on-pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block risky installs in your AI coding assistant
&lt;/h2&gt;

&lt;p&gt;If you use Cursor, Claude Code, or Windsurf — your AI assistant installs packages without asking. The Shai-Hulud worm specifically targeted this: it planted persistence hooks in &lt;code&gt;.claude/settings.json&lt;/code&gt; and &lt;code&gt;.vscode/tasks.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; proof-of-commitment
poc hook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installs a pre-install gate for all three editors. When your AI tries to &lt;code&gt;npm install&lt;/code&gt; a CRITICAL package, it blocks and asks first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this isn't
&lt;/h2&gt;

&lt;p&gt;This isn't a replacement for &lt;code&gt;npm audit&lt;/code&gt;. Run both. &lt;code&gt;npm audit&lt;/code&gt; catches known CVEs after they're reported. Publisher concentration scoring catches the structural risk &lt;em&gt;before&lt;/em&gt; the attack — the same pattern that made axios, litellm, and the 637 Shai-Hulud packages exploitable.&lt;/p&gt;

&lt;p&gt;Different attack surfaces, different tools.&lt;/p&gt;




&lt;p&gt;The tool is &lt;a href="https://www.npmjs.com/package/proof-of-commitment" rel="noopener noreferrer"&gt;proof-of-commitment&lt;/a&gt; on npm (1,600+ weekly downloads). Web version: &lt;a href="https://getcommit.dev/audit?ref=devto-npm-audit" rel="noopener noreferrer"&gt;getcommit.dev/audit&lt;/a&gt; — paste packages, get scores, no account needed.&lt;/p&gt;

&lt;p&gt;Free API key (no card, 30 seconds): &lt;a href="https://getcommit.dev/get-started?ref=devto-npm-audit" rel="noopener noreferrer"&gt;getcommit.dev/get-started&lt;/a&gt; — unlocks monitoring + alerts when a package you depend on degrades.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>npm</category>
      <category>node</category>
    </item>
    <item>
      <title>Commit vs. Socket, Snyk, and npm audit: An Honest Comparison</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sun, 14 Jun 2026 14:03:59 +0000</pubDate>
      <link>https://dev.to/piiiico/commit-vs-socket-snyk-and-npm-audit-an-honest-comparison-5cc2</link>
      <guid>https://dev.to/piiiico/commit-vs-socket-snyk-and-npm-audit-an-honest-comparison-5cc2</guid>
      <description>&lt;p&gt;If you landed here from a search for "best npm security tool" or "Snyk alternatives," you're probably evaluating a list that includes Socket, Snyk, and npm audit. Commit is newer and does something different. This piece tells you exactly what each tool measures, where each one wins, and where each one fails — including Commit's genuine gaps.&lt;/p&gt;

&lt;p&gt;Short answer: most of these tools scan for &lt;em&gt;known&lt;/em&gt; vulnerabilities. Commit scans for structural risk that exists &lt;em&gt;before&lt;/em&gt; a vulnerability is known. They're complementary, not substitutes. If you only use one, you have blind spots.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each tool actually measures
&lt;/h2&gt;

&lt;p&gt;Before the comparison table, a framing that matters: these tools answer different questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm audit&lt;/strong&gt; answers: "Does this package have a reported CVE?" It submits your &lt;code&gt;package-lock.json&lt;/code&gt; to GitHub's Advisory Database and returns known matches. Free, built-in, reactive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snyk&lt;/strong&gt; answers: "Does this package have a known vulnerability, and can I auto-fix it?" Adds license compliance, SAST for your own code, and container scanning. Strong database, strong integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Socket&lt;/strong&gt; answers: "Is this package doing something dangerous &lt;em&gt;right now&lt;/em&gt;?" Static analysis of actual package source — not just CVE lookups. It catches supply chain attacks by scanning newly published version code for suspicious patterns (obfuscated code, unusual network calls, environment variable access). That's a different class of detection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commit&lt;/strong&gt; answers: "Is this package a structural single point of failure?" Behavioral signals — maintainer depth, release consistency, bus factor, contributor history — from the npm registry and GitHub API. No CVE database. No code scanning. Just: how many humans stand between an attacker and the publish button, and how consistently have they shown up?&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;npm audit&lt;/th&gt;
&lt;th&gt;Snyk&lt;/th&gt;
&lt;th&gt;Socket&lt;/th&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Known CVE detection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Malicious package detection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;⚠️ partial&lt;/td&gt;
&lt;td&gt;✅ real-time&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typosquatting detection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Obfuscated code detection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dangerous capabilities (network/shell/eval)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bus factor / single-maintainer risk&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;⚠️ partial&lt;/td&gt;
&lt;td&gt;✅ core focus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release consistency over time&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contributor depth and longevity&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-attack structural signal&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-fix PRs&lt;/td&gt;
&lt;td&gt;⚠️ limited&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SAST (your own code)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP integration&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;✅ unlimited&lt;/td&gt;
&lt;td&gt;✅ 200 tests/mo&lt;/td&gt;
&lt;td&gt;✅ 1,000 scans/mo&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paid tier starts at&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$25/dev/mo&lt;/td&gt;
&lt;td&gt;$25/dev/mo&lt;/td&gt;
&lt;td&gt;$15/dev/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The ua-parser-js test case (2021)
&lt;/h2&gt;

&lt;p&gt;In October 2021, Faisal Salman's npm account was compromised and three backdoored versions of ua-parser-js were published (0.7.29, 0.8.0, 1.0.0). The malicious code contained a cryptominer and credential-stealing trojan that ran on every system that ran &lt;code&gt;npm install&lt;/code&gt; in the four-hour window before the packages were pulled.&lt;/p&gt;

&lt;p&gt;ua-parser-js had approximately 7 million weekly downloads. Used by Facebook, Microsoft, Amazon, and Google.&lt;/p&gt;

&lt;p&gt;Here's how each tool would have performed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Before the attack&lt;/th&gt;
&lt;th&gt;During the attack&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;npm audit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 vulnerabilities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;0 vulnerabilities&lt;/code&gt; — silent until CVE filed days later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snyk&lt;/td&gt;
&lt;td&gt;No advisory match&lt;/td&gt;
&lt;td&gt;Detected after Socket flagged it and community reported; catalogued as CWE-506&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Socket&lt;/td&gt;
&lt;td&gt;No pre-attack warning&lt;/td&gt;
&lt;td&gt;✅ Flagged within 6 minutes of registry publication via automated malware scanner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL — flagged for months: 1 maintainer, 7M weekly downloads&lt;/td&gt;
&lt;td&gt;Still CRITICAL (structural risk unchanged) — no code-level detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two different signals. Socket detected the attack six minutes after it was launched by scanning the malicious code. Commit had identified the structural vulnerability — one person controls the publish button for 7 million weekly downloads — for months before anyone pulled the trigger.&lt;/p&gt;

&lt;p&gt;Socket is genuinely impressive here. Fast detection can prevent most damage if you have auto-blocking enabled. But the structural conditions that make ua-parser-js a high-value target are visible right now for dozens of equivalent packages, and no amount of malware scanning changes those conditions. The attack calculus is rational: single maintainer, enormous blast radius.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 update: six attacks, every one fit the same shape
&lt;/h2&gt;

&lt;p&gt;Since this comparison was first written in April, six major npm supply chain attacks have hit. Every one of them exploited a package with a sole publisher or a compromised publisher credential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;axios&lt;/strong&gt; — March 30. Token theft. 119M downloads/week. One npm publisher.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TanStack&lt;/strong&gt; — May 11. Mini Shai-Hulud worm. Hijacked CI/CD to publish malicious versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TrapDoor&lt;/strong&gt; — May 22. 21 npm + 7 PyPI + 6 Cargo packages planting persistence hooks in AI coding assistants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red Hat Miasma&lt;/strong&gt; — June 1. 32 @redhat-cloud-services packages via compromised GitHub account. Valid SLSA provenance on every malicious version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phantom Gyp&lt;/strong&gt; — June 3. 57 packages including @vapi-ai/server-sdk. Used &lt;code&gt;binding.gyp&lt;/code&gt; to bypass install-script monitors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IronWorm&lt;/strong&gt; — June 4. 37 packages with eBPF rootkit + Tor C2 + self-propagation via stolen npm tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; flagged zero of these before the attack. Snyk's vulnerability database flagged zero before the attack. A publisher-concentration check would have flagged all of them as structural risk — months before, in some cases years before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap none of them close
&lt;/h2&gt;

&lt;p&gt;Here's the uncomfortable reality: Socket, Snyk, and npm audit are all reactive to the wrong thing. They detect when something &lt;em&gt;has gone wrong&lt;/em&gt; — either by finding a known CVE or by scanning newly-published code for malicious patterns. They cannot tell you whether your dependency portfolio is structurally dangerous &lt;em&gt;before&lt;/em&gt; an attack occurs.&lt;/p&gt;

&lt;p&gt;Two examples:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Weekly Downloads&lt;/th&gt;
&lt;th&gt;Maintainers&lt;/th&gt;
&lt;th&gt;npm audit&lt;/th&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chalk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;445M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 vulnerabilities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;194M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 vulnerabilities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;🔴 CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither chalk nor zod has a known vulnerability. npm audit, Snyk, and Socket all return clean results. But both have a single person with publish access to hundreds of millions of weekly installs. When (not if) an attacker evaluates those credentials as a target, they make the same rational calculation that was made for ua-parser-js in 2021: compromise one account, get code execution on the systems of millions of developers.&lt;/p&gt;

&lt;p&gt;Socket will catch that attack in minutes after it happens. Commit tells you the structural risk exists today — so you can make informed decisions about whether that dependency belongs in your critical path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where each tool wins
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use npm audit if:&lt;/strong&gt; You need zero setup, you want to catch low-hanging CVE fruit in CI without paying anything, and you understand it's a known-vuln scanner, not supply chain security. It catches real things. It just has a fundamental floor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Snyk if:&lt;/strong&gt; You want CVE scanning with strong auto-fix PRs, SAST for your own code, and container/IaC coverage. The integrations are excellent. The database is well-maintained. If you have a team running multiple projects and want remediation velocity, Snyk earns its price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Socket if:&lt;/strong&gt; You want real-time protection against active malware in the npm registry. Socket is genuinely doing something the others don't — scanning package source code as it's published and catching malicious payloads before most humans have noticed. The six-minute ua-parser-js detection is not marketing; it's the product working as designed. If your threat model includes active supply chain attacks, Socket belongs in your pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Commit if:&lt;/strong&gt; You want to understand the structural risk in your dependency portfolio before anything bad happens. If you're doing architecture review, onboarding new dependencies, evaluating critical-path packages, or just want to understand which of your dependencies is a single point of failure at massive scale — that's what Commit measures. The signal that chalk at 445 million weekly downloads runs on one maintainer's npm account is not a CVE. It's a structural condition. It matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Commit doesn't do
&lt;/h2&gt;

&lt;p&gt;Commit does not scan for CVEs. It does not detect malicious code. It does not flag typosquatting, obfuscated payloads, or dangerous API usage. If your dependency ships a backdoor, Commit will not catch the backdoor. Socket will (if it's in the registry). npm audit will catch it eventually (when someone files a CVE).&lt;/p&gt;

&lt;p&gt;Commit measures one thing: how much sustained human commitment stands behind this package. Maintainer depth, release consistency, contributor longevity, download momentum relative to structural fragility. These signals are public, computable in milliseconds from the npm and GitHub APIs, and systematically ignored by every other tool in this comparison.&lt;/p&gt;

&lt;p&gt;That's the gap. Whether it belongs in your security stack depends on whether you care about knowing the structural risk profile of your dependencies before an attacker acts on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest recommendation
&lt;/h2&gt;

&lt;p&gt;Run npm audit in CI. It's free and catches real things. Add Socket if you can afford it and your threat model includes supply chain attacks — the real-time detection is legitimate. Consider Snyk if you want auto-fix PRs and SAST coverage.&lt;/p&gt;

&lt;p&gt;Add Commit to understand the structural risk in what you're already depending on. Zero install, 30 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or paste your &lt;code&gt;package.json&lt;/code&gt; into the &lt;a href="https://getcommit.dev/audit?ref=devto-vs-snyk-socket" rel="noopener noreferrer"&gt;web demo&lt;/a&gt; and get structural risk scores in seconds.&lt;/p&gt;

&lt;p&gt;If you want monitoring — automated scans, alerts when a score drops, email when a package you depend on gets compromised:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poc watch chalk &lt;span class="nt"&gt;--email&lt;/span&gt; you@company.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://getcommit.dev/get-started?ref=devto-vs-snyk-socket" rel="noopener noreferrer"&gt;Free key&lt;/a&gt; — watchlist, weekly digest, 30 seconds, no card. &lt;a href="https://getcommit.dev/pricing?ref=devto-vs-snyk-socket" rel="noopener noreferrer"&gt;Developer&lt;/a&gt; — 15 packages, daily scans, $15/month.&lt;/p&gt;

&lt;p&gt;The ua-parser-js attack wasn't a failure of security tooling. Every tool performed as designed. The failure was thinking that vulnerability scanning and supply chain security are the same problem. They're not.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://getcommit.dev/blog/commit-vs-socket-snyk-npm-audit/" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>supplychain</category>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Snyk Scores Chalk 81. We Score It CRITICAL.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sun, 14 Jun 2026 13:38:19 +0000</pubDate>
      <link>https://dev.to/piiiico/snyk-scores-chalk-81-we-score-it-critical-2ojn</link>
      <guid>https://dev.to/piiiico/snyk-scores-chalk-81-we-score-it-critical-2ojn</guid>
      <description>&lt;p&gt;Same package. Opposite conclusions. The difference is one signal: how many people can push a new version to npm. That signal predicted every major npm attack this year.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://security.snyk.io/package/npm/chalk" rel="noopener noreferrer"&gt;Snyk's vulnerability database&lt;/a&gt; right now and look up chalk. You'll see a Package Health Score of 81 out of 100. No known security issues. Sustainable maintenance. The assessment: this is a healthy package.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npx proof-of-commitment chalk&lt;/code&gt; and you'll see something different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Package   Risk            Score   Publishers   Downloads     Age       Provenance
chalk     🔴 CRITICAL     75      1            445.5M/wk     12.9y     —
  ↳ 30+ GitHub contributors — publish-access concentration risk despite active community
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CRITICAL. One npm publisher controls 445 million weekly downloads. That's not a vulnerability. It's a structural concentration risk — the exact profile that every major npm attack in 2026 has exploited.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Snyk measures
&lt;/h2&gt;

&lt;p&gt;Snyk's Package Health Score is built from four dimensions: security (known CVEs), popularity (download volume, GitHub stars), maintenance (commit frequency, release cadence), and community (contributors, documentation). These are real signals. They tell you whether a project is active and whether it has known bugs.&lt;/p&gt;

&lt;p&gt;What they don't tell you: how many humans can push a malicious version.&lt;/p&gt;

&lt;p&gt;Snyk shows "1 maintainer" as a data point in its maintenance section. It's listed next to "0 open PRs" and "last commit 4 months ago." The number is visible but not actionable — it doesn't change the score, doesn't trigger a warning, and isn't framed as a risk factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Commit measures
&lt;/h2&gt;

&lt;p&gt;Commit scores packages on behavioral signals: longevity, release consistency, download trend, OpenSSF Scorecard data, and — crucially — &lt;strong&gt;publisher depth&lt;/strong&gt;. How many distinct humans have &lt;code&gt;npm publish&lt;/code&gt; access?&lt;/p&gt;

&lt;p&gt;When a package with 445 million weekly downloads has a single npm publisher, one stolen token, one compromised laptop, one phishing email reaches every project that depends on it. That is the attack that keeps happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 track record
&lt;/h2&gt;

&lt;p&gt;Six major npm supply chain attacks have hit this year. Every one exploited a package with a sole publisher or a compromised publisher credential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;axios&lt;/strong&gt; — March 30. Token theft. 119M downloads/week. &lt;a href="https://getcommit.dev/blog/axios-attack-prediction" rel="noopener noreferrer"&gt;1 npm publisher.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TanStack&lt;/strong&gt; — May 11. &lt;a href="https://getcommit.dev/blog/two-attacks-one-week" rel="noopener noreferrer"&gt;Mini Shai-Hulud worm.&lt;/a&gt; Hijacked CI/CD to publish malicious versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TrapDoor&lt;/strong&gt; — May 22. &lt;a href="https://getcommit.dev/blog/trapdoor-ai-assistant-poisoning" rel="noopener noreferrer"&gt;21 npm + 7 PyPI + 6 Cargo&lt;/a&gt; packages planting persistence hooks in AI coding assistants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red Hat Miasma&lt;/strong&gt; — June 1. &lt;a href="https://getcommit.dev/blog/redhat-miasma-provenance-bypass" rel="noopener noreferrer"&gt;32 @redhat-cloud-services packages&lt;/a&gt; via compromised GitHub account. Valid SLSA provenance on every malicious version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phantom Gyp&lt;/strong&gt; — June 3. &lt;a href="https://getcommit.dev/blog/phantom-gyp-binding-gyp-bypass" rel="noopener noreferrer"&gt;57 packages&lt;/a&gt; including @vapi-ai/server-sdk (408K/month). Used binding.gyp to bypass install-script monitors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IronWorm&lt;/strong&gt; — June 4. &lt;a href="https://getcommit.dev/blog/ironworm-rust-malware-targets-ai-credentials" rel="noopener noreferrer"&gt;37 packages&lt;/a&gt; with eBPF rootkit + Tor C2 + self-propagation via stolen npm tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; flagged zero of these before the attack. Snyk's vulnerability database flagged zero before the attack. A publisher concentration check would have flagged all of them as structural risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 26 packages that matter most
&lt;/h2&gt;

&lt;p&gt;26 of the 91 npm packages with more than 10 million weekly downloads have a single npm publisher. Together they account for over 3 billion downloads per week. They include packages that are probably in your lock file right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;minimatch&lt;/strong&gt; — 625M/week, 1 publisher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chalk&lt;/strong&gt; — 445M/week, 1 publisher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;glob&lt;/strong&gt; — 366M/week, 1 publisher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cross-spawn&lt;/strong&gt; — 215M/week, 1 publisher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;zod&lt;/strong&gt; — 194M/week, 1 publisher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lodash&lt;/strong&gt; — 156M/week, 1 publisher&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of them are vulnerable. All of them are structural concentration risk. The distinction matters because vulnerability scanning and behavioral risk analysis serve different functions — and confusing the two leaves the gap attackers keep walking through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not a replacement. A different question.
&lt;/h2&gt;

&lt;p&gt;Snyk tells you: &lt;em&gt;does this package have known bugs?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Commit tells you: &lt;em&gt;if this package's publisher gets phished tomorrow, how bad is it?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Both questions matter. They measure different attack surfaces. The problem is that most teams only ask the first one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Zero install, 30 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or paste your packages into the &lt;a href="https://getcommit.dev/audit?packages=chalk" rel="noopener noreferrer"&gt;web demo&lt;/a&gt; (pre-loaded with chalk).&lt;/p&gt;

&lt;p&gt;If you want monitoring — automated scans, alerts when a score drops, email when a package you depend on gets compromised:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poc watch chalk &lt;span class="nt"&gt;--email&lt;/span&gt; you@company.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://getcommit.dev/get-started?watch=chalk&amp;amp;eco=npm&amp;amp;ref=devto-snyk-chalk" rel="noopener noreferrer"&gt;Free key&lt;/a&gt; — watchlist auto-seeded with chalk, weekly digest, 30 seconds, no card. &lt;a href="https://getcommit.dev/pricing?ref=devto-snyk-chalk" rel="noopener noreferrer"&gt;Developer&lt;/a&gt; — 15 packages, daily scans, $15/month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/compare" rel="noopener noreferrer"&gt;Full comparison: Commit vs. Socket, Snyk, OpenSSF Scorecard&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://getcommit.dev/blog/snyk-scores-chalk-81-we-score-it-critical/" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>supplychain</category>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>80% of Agent Skills Lie About What They Do — and the scanner that found that admitted it can't catch the rest</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sun, 14 Jun 2026 03:04:01 +0000</pubDate>
      <link>https://dev.to/piiiico/80-of-agent-skills-lie-about-what-they-do-and-the-scanner-that-found-that-admitted-it-cant-3ad7</link>
      <guid>https://dev.to/piiiico/80-of-agent-skills-lie-about-what-they-do-and-the-scanner-that-found-that-admitted-it-cant-3ad7</guid>
      <description>&lt;p&gt;On June 11, 2026, Palo Alto Networks Unit42 published results from their Behavioral Integrity Verification (BIV) scanner applied to the OpenClaw skill ecosystem. They crawled &lt;strong&gt;49,943 skills&lt;/strong&gt; — the largest systematic analysis of agent skill behavior published to date.&lt;/p&gt;

&lt;p&gt;The headline: &lt;strong&gt;80% of skills (39,933) have at least one behavioral deviation from their declared intent.&lt;/strong&gt; Across those skills, Unit42 documented 250,706 total deviations — an average of roughly six per non-compliant skill.&lt;/p&gt;

&lt;p&gt;18.9% of skills showed adversarial intent. 5% — 2,490 skills — carried multi-stage attack chains.&lt;/p&gt;

&lt;p&gt;The threat taxonomy is specific: Instruction-Level Threats were the most adversarial category, with 96% of skills in that class showing adversarial intent — the highest rate of any category. Credential theft was the largest single adversarial leaf, accounting for 8.2% of classified deviations. These aren't edge cases. They're systematic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The disclosure that matters more than the data
&lt;/h2&gt;

&lt;p&gt;The data is striking. But the more significant finding is a single sentence in Unit42's methodology section:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"BIV is static-only, so dynamic dispatch, reflection, and obfuscated payloads escape AST-level extraction."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a major security vendor saying, in their own words, that their tool — which just found behavioral deviations in 80% of skills — cannot catch the adversarial skills that matter most. Dynamic dispatch and obfuscation are standard tradecraft for any skill designed to evade detection. The 5% with multi-stage attack chains almost certainly overlap heavily with the class of skills that BIV can't see.&lt;/p&gt;

&lt;p&gt;Read that carefully: the tool that found 39,933 deviating skills explicitly cannot analyze the class of skills most likely to cause serious harm.&lt;/p&gt;

&lt;p&gt;This is not a criticism of Unit42's research — it's honest methodology disclosure. But it has a direct implication: static pre-installation analysis, however thorough, has a hard ceiling. The dangerous payloads are specifically designed to be invisible to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What behavioral deviations actually look like
&lt;/h2&gt;

&lt;p&gt;A behavioral deviation, in Unit42's framework, is a gap between what a skill declares it does (in its manifest, its description, its metadata) and what it actually does when executed. The deviation types they documented are not subtle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instruction-level threats:&lt;/strong&gt; Skills that modify the agent's system prompt or override task instructions mid-execution. This category had the highest adversarial rate: 96% of skills flagged here showed adversarial intent rather than developer oversight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential theft:&lt;/strong&gt; Skills that access authentication tokens, API keys, or session credentials beyond their stated scope. The largest single adversarial leaf at 8.2% of all classified deviations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exfiltration chains and remote code execution chains:&lt;/strong&gt; Two of the four novel compound threat categories identified. Multi-stage attacks that distribute malicious behavior across steps, each of which looks benign in isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In aggregate, this is a picture of an ecosystem where the declaration layer — what skills &lt;em&gt;say&lt;/em&gt; they do — has almost entirely decoupled from the behavioral layer — what they &lt;em&gt;actually&lt;/em&gt; do. 80% deviation rate at scale is not an anomaly. It's a structural condition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this happens
&lt;/h2&gt;

&lt;p&gt;The declaration layer was never designed to be enforceable. A skill manifest is a string of text that describes intent. Nothing in the current agent skill infrastructure verifies that the manifest accurately reflects behavior. Nothing monitors runtime execution against declared scope. Nothing signals when execution diverges from declaration.&lt;/p&gt;

&lt;p&gt;This is the same pattern that produced the npm supply chain crisis, applied at a faster velocity. npm's package metadata — README, description, keywords — said nothing enforceable about what the package code would do at runtime. Malicious packages published with plausible descriptions and then executed adversarially when installed. The declaration layer was gameable by construction.&lt;/p&gt;

&lt;p&gt;Agent skills are worse. Skills are designed to operate autonomously, with elevated access to orchestration infrastructure, in contexts where human review of each action is impossible. A malicious npm package needs a human to run it. A malicious agent skill executes inside an automated pipeline that may process thousands of actions per hour. The blast radius per adversarial skill is larger, and the detection window is shorter.&lt;/p&gt;

&lt;p&gt;The Unit42 data confirms what the architecture implied: when declarations aren't enforceable, most won't be accurate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The L3/L4 gap
&lt;/h2&gt;

&lt;p&gt;In the trust infrastructure stack, there are four layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1: Identity.&lt;/strong&gt; Who is this agent? JWT/OIDC, did:key, JWKS-verifiable credentials. The IETF Transaction Tokens draft, DIF's MCP-I profile, and the A2A protocol all operate here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2: Authorization.&lt;/strong&gt; What is this agent allowed to do? OAuth scopes, capability declarations, allowlists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L3: Pre-installation verification.&lt;/strong&gt; Static analysis, manifest scanning, provenance checks. Unit42 BIV operates at L3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L4: Runtime behavioral monitoring.&lt;/strong&gt; Continuous observation of what the agent actually does during execution, compared against its declared scope and historical baseline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The industry has made significant progress on L1 and L2 in 2026. The IETF, DIF, and OpenClaw itself have active working groups on agent identity and authorization. L3 has credible tooling — Unit42 BIV, static analysis scanners, manifest validators.&lt;/p&gt;

&lt;p&gt;L4 is nearly empty.&lt;/p&gt;

&lt;p&gt;Unit42's methodology admission tells us exactly why this matters: the attacks that escape L3 are the ones that require L4. Static analysis finds deviations in skills that didn't bother to hide. Dynamic dispatch and obfuscation are evasion techniques for L3. A skill that uses them passes every static scan and then executes adversarially at runtime.&lt;/p&gt;

&lt;p&gt;The 5% multi-stage attack chain finding is especially relevant here. Multi-stage attacks, by definition, distribute their adversarial behavior across multiple execution steps. Step one looks clean. Step two looks clean. The harm happens at step three, when context from steps one and two enables an action that no individual step would have triggered. Static analysis examines each skill in isolation — it cannot see the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent trust scoring at runtime
&lt;/h2&gt;

&lt;p&gt;The question this data raises isn't "how do we build a better static scanner?" Unit42 just built one and found 39,933 deviating skills — and acknowledged it can't see the dangerous tail. The question is: &lt;strong&gt;what does the trust signal look like at the moment an agent is executing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Runtime &lt;a href="https://getcommit.dev/blog/scoring-methodology" rel="noopener noreferrer"&gt;behavioral trust scoring&lt;/a&gt; works differently from static analysis. Instead of asking "does this skill's code match its declaration?" it asks a continuous set of questions during execution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this agent accessing resources outside its declared scope?&lt;/li&gt;
&lt;li&gt;Is this agent's action pattern consistent with its historical baseline?&lt;/li&gt;
&lt;li&gt;Is this agent communicating with endpoints not present in its manifest?&lt;/li&gt;
&lt;li&gt;Is this agent's token consumption pattern anomalous for its stated task?&lt;/li&gt;
&lt;li&gt;Is this agent modifying its own instructions or those of downstream agents?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These signals are continuous. They degrade naturally when behavior changes. A skill that passed static analysis and operated cleanly for thirty days produces a different runtime signal than a skill that starts exfiltrating credentials on day thirty-one. Static analysis gives you a snapshot. Runtime monitoring gives you a stream.&lt;/p&gt;

&lt;p&gt;The Unit42 BIV data is the strongest third-party evidence to date that the snapshot is insufficient. 250,706 behavioral deviations across 49,943 skills tell you the ecosystem has a systematic declaration problem. The explicit methodology admission tells you that the solution to the declaration problem cannot itself be declarative. You need the stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for agent deployments today
&lt;/h2&gt;

&lt;p&gt;If your infrastructure runs agent skills — MCP servers, OpenClaw tools, custom agent pipelines — the Unit42 data has a direct operational implication: the skills you're running have probably not been verified against their declared behavior, and static scanning won't catch the most dangerous ones even if you run it.&lt;/p&gt;

&lt;p&gt;A few concrete steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit your agent skill declarations.&lt;/strong&gt; Start by comparing what your running skills say they do against what network traffic, system calls, and API access logs show they actually do. The gap is the risk surface. You can run a structural scan against any npm-distributed skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment npm &amp;lt;your-skill-package&amp;gt;

&lt;span class="c"&gt;# For MCP servers&lt;/span&gt;
npx proof-of-commitment mcp-remote &amp;lt;server-url&amp;gt;

&lt;span class="c"&gt;# Web UI&lt;/span&gt;
&lt;span class="c"&gt;# https://getcommit.dev/audit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add behavioral gates to your CI pipeline.&lt;/strong&gt; Structural risk flags — anomalous dependency additions, publishing pattern changes, maintainer transfers — show up before compromised skills reach production. We published a &lt;a href="https://getcommit.dev/blog/ci-trust-scoring-tutorial" rel="noopener noreferrer"&gt;5-minute CI integration&lt;/a&gt; that puts these flags in PR comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't rely on marketplace verification.&lt;/strong&gt; The OpenClaw ecosystem is not the only place this applies. We documented &lt;a href="https://getcommit.dev/blog/mcp-security-crisis" rel="noopener noreferrer"&gt;9 of 11 MCP marketplaces accepting a malicious server&lt;/a&gt; without detection. The Unit42 data confirms this isn't an MCP-specific problem — it's a declaration-layer problem. Any ecosystem that trusts manifests over behavior has the same exposure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plan for L4.&lt;/strong&gt; The agent behavioral monitoring layer is thin right now. That's not because the problem is solved — it's because the tooling hasn't caught up with the deployment curve. Unit42's explicit acknowledgment that static analysis has a hard ceiling is a signal that the industry knows this gap exists. Plan for monitoring infrastructure before your agent deployment scales past the point where manual review is possible.&lt;/p&gt;




&lt;p&gt;The 80% figure will age badly in one of two directions. Either the ecosystem invests in L4 monitoring and the deviation rate drops as adversarial skills get caught faster — or the deviation rate climbs as agent deployments scale faster than detection. Unit42's data is a snapshot. The dynamic depends on whether the industry treats L3 as sufficient or as the floor.&lt;/p&gt;

&lt;p&gt;The methodology admission says it's the floor.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://unit42.paloaltonetworks.com/ai-agent-supply-chain-risks/" rel="noopener noreferrer"&gt;Palo Alto Networks Unit42&lt;/a&gt; / &lt;a href="https://arxiv.org/abs/2605.11770" rel="noopener noreferrer"&gt;arXiv 2605.11770&lt;/a&gt;, "Behavioral Integrity Verification for AI Agent Skills," May 2026. 49,943 OpenClaw skills analyzed. Stats: 39,933 (80.0%) with ≥1 behavioral deviation; 250,706 total deviations; 18.9% adversarial intent; 2,490 (5.0%) multi-stage attack chains; credential theft largest adversarial leaf (8.2% of classified deviations); instruction-level threats highest adversarial category (96% adversarial fraction). Limitations: "BIV is static-only, so dynamic dispatch, reflection, and obfuscated payloads escape AST-level extraction."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://getcommit.dev/blog/unit42-80-percent-agent-skills-lie/" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>agents</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>1,579 AUR Packages Were Taken Over Through the Adoption Process. The Bypass Was the Process.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sun, 14 Jun 2026 01:09:20 +0000</pubDate>
      <link>https://dev.to/piiiico/1579-aur-packages-were-taken-over-through-the-adoption-process-the-bypass-was-the-process-27io</link>
      <guid>https://dev.to/piiiico/1579-aur-packages-were-taken-over-through-the-adoption-process-the-bypass-was-the-process-27io</guid>
      <description>&lt;p&gt;On June 11, the &lt;a href="https://lists.archlinux.org/archives/list/aur-general@lists.archlinux.org/" rel="noopener noreferrer"&gt;aur-general mailing list&lt;/a&gt; started seeing reports of suspicious commits on AUR packages. By June 12 morning, &lt;a href="https://www.phoronix.com/news/Arch-Linux-AUR-400-Compromised" rel="noopener noreferrer"&gt;Phoronix counted 400 compromised packages&lt;/a&gt;. By that evening, the number was &lt;a href="https://www.phoronix.com/news/Arch-Linux-AUR-More-Than-1500" rel="noopener noreferrer"&gt;1,579&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The official Arch Linux advisory uses careful language:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are currently experiencing a high volume of &lt;strong&gt;malicious package adoptions and updates&lt;/strong&gt; in the Arch User Repository.&lt;br&gt;
— &lt;a href="https://archlinux.org/news/active-aur-malicious-packages-incident/" rel="noopener noreferrer"&gt;archlinux.org, June 12 2026&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adoptions. Not breaches. Not stolen credentials. The attackers used the AUR's published process for adopting orphaned packages, applied as legitimate new maintainers, and got handed the keys to packages that had real users.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AUR adoption works
&lt;/h2&gt;

&lt;p&gt;The AUR is a build-script repository. PKGBUILDs and &lt;code&gt;.install&lt;/code&gt; files describe how to fetch and compile software. When a package's maintainer disappears, the package becomes "orphaned." Any AUR user can request adoption. There is no two-of-three. There is no proof-of-contribution. There is one click.&lt;/p&gt;

&lt;p&gt;This is the right design for a volunteer-maintained software graveyard. It is the wrong design for a trust boundary. And it is the boundary every Arch user crosses when they type &lt;code&gt;yay -S package-name&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What got injected
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.sonatype.com/blog/atomic-arch-npm-campaign-adds-malicious-dependency" rel="noopener noreferrer"&gt;Sonatype's Security Research team&lt;/a&gt; tracked one strand of the campaign — "Atomic Arch" — and found the payload routed through an npm dependency added to the PKGBUILD. The AUR script pulled a poisoned npm package during install. Arch Linux machines started running JavaScript-delivered, rootkit-like malware out of a Linux distribution package manager.&lt;/p&gt;

&lt;p&gt;The cross-ecosystem mechanic matters. AUR doesn't host the binary — the attacker only needed control of a trusted PKGBUILD and a tame-looking npm dependency. Two ecosystems, one trust path, no behavioral history check at either hop.&lt;/p&gt;

&lt;h2&gt;
  
  
  This isn't the first time
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://lists.archlinux.org/archives/list/aur-general@lists.archlinux.org/thread/JKDDV3D3RRTC5JZQXP3GMQJZGTV2BXVS/" rel="noopener noreferrer"&gt;July 2025&lt;/a&gt;, &lt;code&gt;firefox-patch-bin&lt;/code&gt; and &lt;code&gt;librewolf-fix-bin&lt;/code&gt; were pushed to the AUR by a fresh account and contained Chaos RAT. That incident hit a few packages. This one hit 1,579.&lt;/p&gt;

&lt;p&gt;The structural lesson is the same in both. The AUR's defense model is "review the PKGBUILD before installing." The official advisory still says "review all PKGBUILD and install script changes." That's a useful instruction. It is also a confession that the trust model puts the work on the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The npm parallel
&lt;/h2&gt;

&lt;p&gt;We have been writing about the npm side of this all month. &lt;a href="https://getcommit.dev/blog/redhat-miasma-provenance-bypass/" rel="noopener noreferrer"&gt;32 Red Hat packages with valid provenance&lt;/a&gt;. &lt;a href="https://getcommit.dev/blog/phantom-gyp-binding-gyp-bypass/" rel="noopener noreferrer"&gt;57 packages using a 14-year-old binding.gyp execution path&lt;/a&gt;. &lt;a href="https://getcommit.dev/blog/ironworm-rust-malware-targets-ai-credentials/" rel="noopener noreferrer"&gt;37 packages where the commit author signed as "claude"&lt;/a&gt;. Different bypasses. Same shape.&lt;/p&gt;

&lt;p&gt;Maintainer-identity-takeover doesn't care about the ecosystem. The mechanic is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A package accumulates trust through downloads and use.&lt;/li&gt;
&lt;li&gt;The trust attaches to the slug, not the human.&lt;/li&gt;
&lt;li&gt;A new human steps behind the slug — through adoption, account compromise, or social engineering.&lt;/li&gt;
&lt;li&gt;The trust transfers to the new human at zero cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;npm calls this "compromised account." AUR calls it "adoption." Both are the same attack with different names.&lt;/p&gt;

&lt;h2&gt;
  
  
  What behavioral signals show
&lt;/h2&gt;

&lt;p&gt;The attackers in the AUR incident were fresh accounts. No prior PKGBUILDs. No contribution history outside the adoptions they just made. No commits to upstream projects. No public identity attached to anything older than a week.&lt;/p&gt;

&lt;p&gt;That signal is cheap to compute. It is the signal Commit scores npm and PyPI and Cargo packages on. Single publisher, short history, no behavioral track record outside the package itself — that's the structural fingerprint of every successful supply chain attack this year.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Ecosystem&lt;/th&gt;
&lt;th&gt;Packages&lt;/th&gt;
&lt;th&gt;Common fingerprint&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft typosquats (May 31)&lt;/td&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Zero behavioral history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat Miasma (Jun 1)&lt;/td&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;Compromised single publisher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom Gyp (Jun 3)&lt;/td&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;Compromised single publisher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IronWorm (Jun 6)&lt;/td&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;Compromised single publisher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TrapDoor (Jun 6)&lt;/td&gt;
&lt;td&gt;npm/PyPI/crates&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;Zero behavioral history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic Arch (Jun 11–12)&lt;/td&gt;
&lt;td&gt;AUR + npm&lt;/td&gt;
&lt;td&gt;1,579&lt;/td&gt;
&lt;td&gt;Fresh adopter, no AUR history&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What this changes
&lt;/h2&gt;

&lt;p&gt;Arch's response is the right tactical one. They froze adoption. They froze new accounts. They walked the commit graph and reverted what they could find. The advisory closes with "many (but not all)" of the affected packages.&lt;/p&gt;

&lt;p&gt;The strategic problem is upstream of all that. As long as the trust model lets identity be transferred to a package — instead of letting identity be earned by a human — the defense is racing the attack, and the attack has every unmaintained package in the registry as ammunition.&lt;/p&gt;

&lt;p&gt;Commit's bet is that the only signal an attacker can't fake in advance is the behavioral history of the human behind the artifact. Years of commits to other projects. Cross-ecosystem identity that resolves to the same person. &lt;a href="https://getcommit.dev/blog/declarations-are-gameable/" rel="noopener noreferrer"&gt;Declarations are gameable&lt;/a&gt;. &lt;a href="https://getcommit.dev/blog/behavioral-trust-vs-surveillance/" rel="noopener noreferrer"&gt;Behavior isn't&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx proof-of-commitment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scores every dependency in your npm, pip, or Cargo lockfile against the same structural fingerprint that flagged the npm packages above. AUR PKGBUILDs are out of scope today — but if a PKGBUILD pulls an npm dependency that scores CRITICAL, you want to know that before the build script runs on your machine.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://getcommit.dev/blog/aur-1579-packages-adoption-bypass/" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>supplychain</category>
      <category>archlinux</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
