<?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.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>drizzle-kit Has 8.2M Weekly Downloads and Ships an Archived Dependency With 1 Publisher</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Fri, 29 May 2026 08:41:41 +0000</pubDate>
      <link>https://dev.to/piiiico/drizzle-kit-has-82m-weekly-downloads-and-ships-an-archived-dependency-with-1-publisher-2jh9</link>
      <guid>https://dev.to/piiiico/drizzle-kit-has-82m-weekly-downloads-and-ships-an-archived-dependency-with-1-publisher-2jh9</guid>
      <description>&lt;p&gt;drizzle-kit has 8.2 million weekly downloads, 4 npm publishers, provenance enabled, and a behavioral score of 83. Looked at on its own, it's fine.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install drizzle-kit&lt;/code&gt; also pulls in &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt;. That package's GitHub repo is archived. Its last npm publish was 17 September 2023 — 981 days ago. It has one npm publisher. It gets 7.5 million weekly downloads through Drizzle and a few other consumers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The numbers, side by side
&lt;/h2&gt;

&lt;p&gt;Both packages scored through &lt;a href="https://getcommit.dev/audit" 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;Days since publish&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;drizzle-kit&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8.2M&lt;/td&gt;
&lt;td&gt;69&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@esbuild-kit/esm-loader&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.5M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;981&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HIGH + WARN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;drizzle-kit's own metrics look healthy. The transitive dep does not. &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt; trips two risk flags: &lt;em&gt;sole npm publisher with &amp;gt;1M weekly downloads&lt;/em&gt;, and &lt;em&gt;no release in 12+ months&lt;/em&gt;. The repo is &lt;a href="https://github.com/esbuild-kit/esm-loader" rel="noopener noreferrer"&gt;archived&lt;/a&gt;. The sole maintainer moved their work to &lt;code&gt;tsx&lt;/code&gt; over two years ago.&lt;/p&gt;




&lt;h2&gt;
  
  
  The community already knows
&lt;/h2&gt;

&lt;p&gt;This isn't a surprise to anyone reading Drizzle's issue tracker. At least five open pull requests propose dropping or replacing &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/drizzle-team/drizzle-orm/pull/3498" rel="noopener noreferrer"&gt;PR #3498&lt;/a&gt; — opened 6 November 2024. &lt;em&gt;Move @esbuild-kit/esm-loader to devDependencies.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/drizzle-team/drizzle-orm/pull/4250" rel="noopener noreferrer"&gt;PR #4250&lt;/a&gt; — opened 10 March 2025. &lt;em&gt;Remove @esbuild-kit/esm-loader.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/drizzle-team/drizzle-orm/pull/4430" rel="noopener noreferrer"&gt;PR #4430&lt;/a&gt; — &lt;em&gt;Replace with tsx.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/drizzle-team/drizzle-orm/pull/4819" rel="noopener noreferrer"&gt;PR #4819&lt;/a&gt; — &lt;em&gt;Replace @esbuild-kit/esm-loader with tsx.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/drizzle-team/drizzle-orm/pull/5689" rel="noopener noreferrer"&gt;PR #5689&lt;/a&gt; — opened 27 April 2026. &lt;em&gt;Drop deprecated @esbuild-kit/esm-loader dependency.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus a tracked security issue, &lt;a href="https://github.com/drizzle-team/drizzle-orm/issues/5481" rel="noopener noreferrer"&gt;#5481&lt;/a&gt;, opened 13 March 2026 with 15 thumbs-up reactions and 7 comments. All five PRs are open. The oldest has been open for 18 months.&lt;/p&gt;

&lt;p&gt;This isn't a swipe at Drizzle. The team has shipped a serious ORM and is responsible for an enormous surface area. The point is structural: a healthy package can ship transitive risk for years while the community files PRs that nobody merges. The risk lives one &lt;code&gt;npm install&lt;/code&gt; below the surface where most people stop looking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this pattern keeps recurring
&lt;/h2&gt;

&lt;p&gt;The interesting thing about &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt; isn't that one person published it. Plenty of small dependencies have one maintainer and do fine. The interesting thing is that the maintainer themselves told everyone to stop using it. The repo is archived. The replacement (&lt;code&gt;tsx&lt;/code&gt;, by the same author) is right there.&lt;/p&gt;

&lt;p&gt;That makes this a quieter version of the event-stream pattern: a package whose maintainer's engagement has expired, still being shipped to millions of machines every week. The credential surface narrows to one person who no longer has any active reason to defend it. If that credential is compromised tomorrow, every &lt;code&gt;drizzle-kit&lt;/code&gt; install pulling a fresh tree ships whatever the attacker pushes.&lt;/p&gt;

&lt;p&gt;Drizzle's own score doesn't tell you this. Neither does &lt;code&gt;npm audit&lt;/code&gt;, because there's no CVE: nothing is broken &lt;em&gt;yet&lt;/em&gt;. The behavioral signals — archived repo, single publisher, no release in 981 days — catch the risk before there's a vulnerability to scan for.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this means for your stack
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;drizzle-kit&lt;/code&gt; is in your &lt;code&gt;devDependencies&lt;/code&gt;, you're shipping &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt; into your CI and local dev environments. It runs every time you generate or push migrations. The blast radius is whatever credentials and source those environments touch.&lt;/p&gt;

&lt;p&gt;The fix on Drizzle's side is straightforward — &lt;code&gt;tsx&lt;/code&gt; is a drop-in replacement, written by the same author, actively maintained, score 86. Five PRs are already written. Until one merges, the working answer for users is to pin &lt;code&gt;drizzle-kit&lt;/code&gt; behind a vetted lockfile and watch for changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Find this in your own dependencies
&lt;/h2&gt;

&lt;p&gt;The full transitive tree, scored:&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 use the &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;web audit&lt;/a&gt; for a single package.&lt;/p&gt;

&lt;p&gt;None of this requires waiting for a CVE. Behavioral signals are available the moment the conditions are true. Right now, &lt;code&gt;@esbuild-kit/esm-loader&lt;/code&gt; is on day 981.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/audit?utm_source=devto-drizzle" rel="noopener noreferrer"&gt;Audit your dependencies →&lt;/a&gt; · &lt;a href="https://getcommit.dev/get-started?utm_source=devto-drizzle" rel="noopener noreferrer"&gt;Get free API key →&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The packages included &lt;code&gt;jest-canvas-mock&lt;/code&gt; (2.8M 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; (295K), 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; 637 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 547 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.&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 itself as OpenTelemetry traces, posting to &lt;code&gt;t.m-kosche.com:443/api/public/otel/v1/traces&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Here's where it gets personal for anyone reading this on a machine with Claude Code installed:&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 at &lt;code&gt;~/.local/share/kitty/cat.py&lt;/code&gt; 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;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" rel="noopener noreferrer"&gt;Commit&lt;/a&gt;, a behavioral supply chain scorer. The non-AntV packages — the ones most projects wouldn't think to audit — 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;1K&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;295K&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.8M&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 account 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 publish.&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 39-minute 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 make decisions about which packages to trust.&lt;/p&gt;

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

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stripe and Google Cloud Storage Are Both CRITICAL on npm</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sun, 24 May 2026 20:47:53 +0000</pubDate>
      <link>https://dev.to/piiiico/stripe-and-google-cloud-storage-are-both-critical-on-npm-55c6</link>
      <guid>https://dev.to/piiiico/stripe-and-google-cloud-storage-are-both-critical-on-npm-55c6</guid>
      <description>&lt;p&gt;The &lt;code&gt;stripe&lt;/code&gt; npm package processes payments for millions of businesses. It has 12 million downloads per week and one npm publisher: a service account called &lt;code&gt;stripe-bindings&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If someone compromises that account's credentials, they publish a malicious version to every &lt;code&gt;npm install&lt;/code&gt; in every CI pipeline that depends on &lt;code&gt;stripe&lt;/code&gt;. This is not a theoretical risk. The axios attack in March 2026 followed the same pattern: one publisher, stolen credentials, 97 million machines exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit
&lt;/h2&gt;

&lt;p&gt;I ran five infrastructure packages through &lt;a href="https://getcommit.dev/audit" 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;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;next&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;95&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;37.7M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@aws-sdk/client-s3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;29.1M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;stripe&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12.2M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CRITICAL&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;@google-cloud/storage&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12.4M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CRITICAL&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;prisma&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12.4M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of the five are CRITICAL. Not because Stripe or Google have bad security practices — they don't. But because npm's publish model concentrates access in a single credential.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CRITICAL means
&lt;/h2&gt;

&lt;p&gt;Commit flags a package as CRITICAL when it has a single npm publisher &lt;em&gt;and&lt;/em&gt; more than 10 million weekly downloads. This is the attack surface that the axios, LiteLLM, and event-stream attacks exploited. The attacker doesn't need to find a vulnerability in the code. They need one credential.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stripe&lt;/code&gt; also has &lt;code&gt;hasDangerousWorkflow: true&lt;/code&gt; from the &lt;a href="https://securityscorecards.dev/" rel="noopener noreferrer"&gt;OpenSSF Scorecard&lt;/a&gt;, meaning its GitHub Actions configuration has patterns that could be exploited. Combined with a single publisher, this creates two independent attack paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's NOT at risk
&lt;/h2&gt;

&lt;p&gt;Stripe the company has strong security infrastructure. Their API, dashboard, card processing — those run on systems they control. The risk is the npm distribution channel. The &lt;code&gt;stripe&lt;/code&gt; npm package is the SDK that 12 million weekly installs pull into their applications. A malicious version runs in &lt;em&gt;your&lt;/em&gt; CI pipeline and &lt;em&gt;your&lt;/em&gt; production servers — not Stripe's.&lt;/p&gt;

&lt;h2&gt;
  
  
  The structural fix
&lt;/h2&gt;

&lt;p&gt;Two paths out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add a second npm publisher.&lt;/strong&gt; &lt;code&gt;next&lt;/code&gt; has 4 publishers. &lt;code&gt;@aws-sdk/client-s3&lt;/code&gt; has 2. A second publisher means no single credential compromise gives full publish access. This costs nothing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable npm Trusted Publishing.&lt;/strong&gt; OIDC-based provenance ties every published version to a specific GitHub Actions run. No long-lived tokens to steal.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Compare: &lt;code&gt;prisma&lt;/code&gt; has 12.4M downloads/week and 2 publishers. Not CRITICAL. The difference is one &lt;code&gt;npm owner add&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own 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;span class="nt"&gt;--file&lt;/span&gt; package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or paste packages into the &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;web audit&lt;/a&gt;. The CRITICAL flag shows which of your dependencies have this concentration risk right now.&lt;/p&gt;

&lt;p&gt;Full post with links: &lt;a href="https://getcommit.dev/blog/stripe-google-cloud-critical/" rel="noopener noreferrer"&gt;getcommit.dev/blog/stripe-google-cloud-critical&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>npm</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>AI Slop Is a Commitment Problem</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 23 May 2026 14:42:07 +0000</pubDate>
      <link>https://dev.to/piiiico/ai-slop-is-a-commitment-problem-f2o</link>
      <guid>https://dev.to/piiiico/ai-slop-is-a-commitment-problem-f2o</guid>
      <description>&lt;p&gt;The Hacker News thread has hundreds of points. The title: "AI slop is killing online communities." The top comments are almost all correct.&lt;/p&gt;

&lt;p&gt;Forums are filling with plausible-sounding content that costs nothing to generate. Stack Overflow is shutting down hot questions faster than ever. Subreddits are adding proof-of-humanity gates. The problem isn't that the content is wrong — it's that you can no longer use effort as a proxy for legitimacy.&lt;/p&gt;

&lt;p&gt;That proxy used to work.&lt;/p&gt;

&lt;p&gt;Before LLMs, writing a thoughtful comment required something: time, knowledge, the willingness to be judged publicly. The effort was small — maybe five minutes — but it was real and correlated with having something to say. If someone wrote 200 words explaining a concept, there was a reasonable chance they understood it. Effort was a signal.&lt;/p&gt;

&lt;p&gt;Now it isn't.&lt;/p&gt;

&lt;p&gt;Claude, GPT, Gemini — all can generate 200 plausible words in seconds, with no knowledge, no accountability, no skin in the game. The cost of producing convincing content dropped to zero. The signal broke. Same structural problem that killed SEO link-buying: when you can produce the proxy cheaply enough, the proxy stops working.&lt;/p&gt;

&lt;p&gt;Simon Willison put it directly last week: "Claude Code does not have a professional reputation. It can't take accountability for what it's done." He wasn't criticizing LLMs — he was naming a structural fact. Reputation requires behavioral history. Accountability requires stakes. AI has neither. It produces outputs, not commitments.&lt;/p&gt;

&lt;p&gt;GitHired launched the same week on Product Hunt with exactly this problem in mind — proof-of-work for job applications. Their bet: showing genuine effort (actual code, actual reasoning, actual time) differentiates candidates in a world of AI-polished resumes. They're right about the problem.&lt;/p&gt;

&lt;p&gt;But effort isn't the right frame. Commitment is.&lt;/p&gt;

&lt;p&gt;Effort can be automated convincingly enough, given time. Commitment can't — because commitment means sustained behavior with real costs over real time. Multiple people maintaining a codebase for ten years. Paying invoices on time, every month. Showing up in ways that leave a verifiable trail.&lt;/p&gt;

&lt;p&gt;This is what we built &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;Commit&lt;/a&gt; around. Not effort-as-signal — behavioral commitment as signal.&lt;/p&gt;

&lt;p&gt;When we flag an npm package as CRITICAL because one maintainer controls 100 million weekly downloads, we're not running a security audit. We're measuring the absence of commitment. A healthy package has multiple maintainers who've been contributing for years, consistent releases, organizational backing. These signals survive AI exactly because they require the one thing AI can't fake: repeated, costly, verifiable action sustained over time.&lt;/p&gt;

&lt;p&gt;The numbers are stark. When we scored the top 50 most-downloaded npm packages in April 2026, 15 came back CRITICAL. Together: 2.5 billion weekly downloads running behind a single set of credentials per package. minimatch (562M downloads/week, 1 maintainer). chalk (413M, 1 maintainer). glob (332M, 1 maintainer). The difference between safe and critical isn't popularity or code quality. It's the depth of human commitment behind the package.&lt;/p&gt;

&lt;p&gt;The AI slop problem isn't a content moderation problem. It's a measurement problem. Communities got used to using effort as shorthand for legitimacy. LLMs made that shorthand worthless overnight.&lt;/p&gt;

&lt;p&gt;The answer isn't more moderation. It's better measurement — shifting from "did someone write this?" to "does this person have a verifiable history of showing up?"&lt;/p&gt;

&lt;p&gt;Commit does this for code. The signals we measure — maintainer depth, release cadence, contributor longevity — don't degrade when AI gets better. They get harder to fake, because they compound over time.&lt;/p&gt;

&lt;p&gt;The same logic applies to everything AI slop is breaking. Content trust, community trust, job applications, code quality. In each case, the old proxy is gone. The replacement isn't effort-detection. It's commitment-measurement.&lt;/p&gt;

&lt;p&gt;Slop is cheap. Commitment isn't.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Score your dependencies: &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;getcommit.dev/audit&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>@antv Had 17 npm Publishers When It Was Compromised. That's the Point.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 23 May 2026 08:56:15 +0000</pubDate>
      <link>https://dev.to/piiiico/antv-had-17-npm-publishers-when-it-was-compromised-thats-the-point-21d3</link>
      <guid>https://dev.to/piiiico/antv-had-17-npm-publishers-when-it-was-compromised-thats-the-point-21d3</guid>
      <description>&lt;p&gt;On May 20, 2026, &lt;a href="https://www.microsoft.com/en-us/security/blog/2026/05/20/mini-shai-hulud-compromised-antv-npm-packages-enable-ci-cd-credential-theft/" rel="noopener noreferrer"&gt;Microsoft reported&lt;/a&gt; that @antv npm packages were compromised in the Mini Shai-Hulud campaign. A maintainer account was hijacked and malicious versions were published to widely used data-visualization packages, propagating into libraries like echarts-for-react (1M+ weekly downloads).&lt;/p&gt;

&lt;p&gt;I ran the @antv packages through &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;Commit's behavioral audit&lt;/a&gt;. None scored CRITICAL. That surprised me for about ten seconds — then it clicked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The @antv audit
&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;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;@antv/g6&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;228K&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@antv/g2&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;337K&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@antv/x6&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;109K&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@antv/l7&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;45K&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@antv/s2&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;8K&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Seventeen publishers. Decent Scorecard scores. No CRITICAL flags.&lt;/p&gt;

&lt;p&gt;The attack worked because one of those seventeen accounts was compromised. Behavioral signals that measure &lt;em&gt;publisher concentration&lt;/em&gt; don't catch this shape of attack — they catch a different one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three attacks in two weeks. Three different profiles.
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Publishers&lt;/th&gt;
&lt;th&gt;Vector&lt;/th&gt;
&lt;th&gt;Behavioral flag?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TanStack&lt;/td&gt;
&lt;td&gt;May 11&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;GitHub Actions OIDC token hijack&lt;/td&gt;
&lt;td&gt;No — bypassed publisher layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node-ipc&lt;/td&gt;
&lt;td&gt;May 14&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Sole publisher credential theft&lt;/td&gt;
&lt;td&gt;Yes — CRITICAL before attack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@antv&lt;/td&gt;
&lt;td&gt;May 20&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;Maintainer account compromise&lt;/td&gt;
&lt;td&gt;No — multi-publisher dilutes risk&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;node-ipc is the archetype of publisher concentration risk: one person, 10M+ downloads per week, one compromised credential away from a malicious publish reaching millions of machines. Commit flagged it CRITICAL months before the attack.&lt;/p&gt;

&lt;p&gt;TanStack is a CI/CD pipeline attack. The malicious code ran with valid SLSA provenance because it was published from the legitimate GitHub Actions runner. Publisher count is irrelevant — the attack bypassed the registry entirely.&lt;/p&gt;

&lt;p&gt;@antv sits between them. Multiple publishers raise the cost of compromise but don't eliminate it. One compromised account out of seventeen was enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  No single signal catches everything
&lt;/h2&gt;

&lt;p&gt;This is the uncomfortable truth that tool marketing usually avoids.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publisher concentration&lt;/strong&gt; (what Commit measures) catches node-ipc-shaped attacks. Single point of failure, credential theft, massive blast radius.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process security&lt;/strong&gt; (OpenSSF Scorecard) catches CI/CD pipeline weaknesses. But axios scored 8.0/10 on Scorecard and was still attacked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavioral analysis&lt;/strong&gt; (Socket) catches malicious code patterns at install time. But only after the malicious version is published.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three attacks, three profiles, three different tools. The fantasy of one tool to catch them all is marketing, not security.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Commit does catch
&lt;/h2&gt;

&lt;p&gt;Right now, these npm packages have one publisher and more than 10M weekly downloads:&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;Downloads/wk&lt;/th&gt;
&lt;th&gt;Publishers&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;562M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chalk&lt;/td&gt;
&lt;td&gt;413M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;333M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cross-spawn&lt;/td&gt;
&lt;td&gt;190M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zod&lt;/td&gt;
&lt;td&gt;163M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lodash&lt;/td&gt;
&lt;td&gt;145M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;axios&lt;/td&gt;
&lt;td&gt;109M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hono&lt;/td&gt;
&lt;td&gt;37M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; shows zero vulnerabilities for all of them. When the next credential-theft attack hits npm, behavioral signals will have flagged it. Process scores won't have helped. And when the next CI/CD attack hits, behavioral signals won't help. Scorecard will. Use both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own stack
&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;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or scan directly: &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;getcommit.dev/audit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;Open source on GitHub&lt;/a&gt;. &lt;a href="https://getcommit.dev/pricing/" rel="noopener noreferrer"&gt;Pro tier&lt;/a&gt; adds batch API, monitoring, and alerts.&lt;/p&gt;

</description>
      <category>security</category>
      <category>npm</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I Added OpenSSF Scorecard to getcommit.dev. The Results Tell Two Different Stories.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Fri, 22 May 2026 20:50:56 +0000</pubDate>
      <link>https://dev.to/piiiico/i-added-openssf-scorecard-to-getcommitdev-the-results-tell-two-different-stories-e40</link>
      <guid>https://dev.to/piiiico/i-added-openssf-scorecard-to-getcommitdev-the-results-tell-two-different-stories-e40</guid>
      <description>&lt;p&gt;OpenSSF Scorecard measures whether a project follows secure development practices. Code review enforcement. Branch protection. SLSA provenance. Dangerous workflow detection.&lt;/p&gt;

&lt;p&gt;I've been building &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;, which measures something different: behavioral commitment signals. Publisher depth. Download concentration. Release consistency. Whether a single npm account holds publish access for a package downloaded 440 million times per week.&lt;/p&gt;

&lt;p&gt;Each package audit now returns both scores. The comparison is worth seeing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The seven CRITICAL packages
&lt;/h2&gt;

&lt;p&gt;These are npm packages with one npm publisher + more than 10 million weekly downloads.&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;Behavioral&lt;/th&gt;
&lt;th&gt;Scorecard&lt;/th&gt;
&lt;th&gt;Downloads/wk&lt;/th&gt;
&lt;th&gt;npm publishers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;chalk&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;3.8/10&lt;/td&gt;
&lt;td&gt;440M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minimatch&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;6.2/10&lt;/td&gt;
&lt;td&gt;609M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;glob&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;5.5/10&lt;/td&gt;
&lt;td&gt;358M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lodash&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;7.3/10&lt;/td&gt;
&lt;td&gt;155M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zod&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;5.1/10&lt;/td&gt;
&lt;td&gt;142M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;axios&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;8.0/10&lt;/td&gt;
&lt;td&gt;108M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hono&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;34M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; shows zero vulnerabilities on all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two tools, two attack surfaces
&lt;/h2&gt;

&lt;p&gt;Scorecard answers: &lt;strong&gt;Can an attacker compromise this project's development pipeline?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Behavioral signals answer: &lt;strong&gt;Can an attacker take over this package by compromising one account?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  axios: attacked despite a strong Scorecard
&lt;/h2&gt;

&lt;p&gt;axios scores 8.0/10 on Scorecard. Strong code review, maintained CI, good token permissions. And it was attacked on March 30, 2026.&lt;/p&gt;

&lt;p&gt;How? Stolen npm credentials. The Scorecard-measured process security was intact. The attack bypassed CI by publishing directly to npm with a stolen publisher key.&lt;/p&gt;

&lt;p&gt;Behavioral signals flagged axios as CRITICAL &lt;em&gt;before&lt;/em&gt; the attack. Not because the CI was weak. Because one account held the npm publish key for a package with 108 million weekly downloads.&lt;/p&gt;

&lt;p&gt;Since the attack, axios has adopted Trusted Publishing (OIDC provenance). But the publisher concentration hasn't changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means practically
&lt;/h2&gt;

&lt;p&gt;These scores don't compete. Use them together.&lt;/p&gt;

&lt;p&gt;A package with high behavioral risk &lt;strong&gt;and&lt;/strong&gt; low Scorecard is doubly exposed: both the credential attack surface and the process exploitation surface are open.&lt;/p&gt;

&lt;p&gt;A package with high behavioral risk but strong Scorecard still carries the credential risk — as the axios attack demonstrated.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; shows you neither.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>npm Supply Chain Audit: The Checklist Most Teams Stop Too Early</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Fri, 22 May 2026 09:39:36 +0000</pubDate>
      <link>https://dev.to/piiiico/npm-supply-chain-audit-the-checklist-most-teams-stop-too-early-1h4</link>
      <guid>https://dev.to/piiiico/npm-supply-chain-audit-the-checklist-most-teams-stop-too-early-1h4</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://getcommit.dev/blog/npm-supply-chain-audit-checklist" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In October 2021, ua-parser-js was used by Facebook, Microsoft, Amazon, and Google. It had 7 million weekly downloads. It had no reported CVEs. It had clean code and an active maintainer. Every security tool in the npm ecosystem reported: nothing wrong here.&lt;/p&gt;

&lt;p&gt;Then the maintainer's npm token was compromised. A malicious release deployed a cryptominer and credential stealer to every CI pipeline and production server that ran &lt;code&gt;npm install&lt;/code&gt; that day. The blast radius: four hours, millions of installs, Fortune 500 pipelines.&lt;/p&gt;

&lt;p&gt;The same structural profile — single maintainer, massive download volume, clean code — was present before the attack. It was visible, computable from public data, and nobody was measuring it.&lt;/p&gt;

&lt;p&gt;This is the gap most npm supply chain audits leave open.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three-layer model
&lt;/h2&gt;

&lt;p&gt;A complete npm supply chain audit covers three distinct layers. Most teams run one. Sophisticated teams run two. Almost nobody runs all three — because the third layer only became a standard practice after real-world attacks validated the signal.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Question answered&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Timing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 — Known vulnerabilities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does this version have a documented CVE?&lt;/td&gt;
&lt;td&gt;npm audit, Snyk&lt;/td&gt;
&lt;td&gt;After discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2 — Code-level anomalies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is this package doing something suspicious right now?&lt;/td&gt;
&lt;td&gt;Socket&lt;/td&gt;
&lt;td&gt;At publish time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3 — Structural risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is this package a high-value attack target before any attack occurs?&lt;/td&gt;
&lt;td&gt;proof-of-commitment&lt;/td&gt;
&lt;td&gt;Before the event&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each layer is essential. Each one fails at what the others cover. A supply chain audit that uses only one or two is a partial audit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 1: Known vulnerability scanning
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; submits your dependency tree to GitHub's Advisory Database and returns matches. Snyk extends this with a proprietary database, license compliance checking, and auto-fix pull requests. Both tools answer the same question: does this package version have a documented, reported vulnerability?&lt;/p&gt;

&lt;h3&gt;
  
  
  What it catches
&lt;/h3&gt;

&lt;p&gt;Prototype pollution vulnerabilities. Known RCE bugs. Packages with published CVEs where the fix is a version bump. The entire category of "known bad" code.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it misses
&lt;/h3&gt;

&lt;p&gt;Anything that isn't documented yet. A CVE requires discovery, analysis, and reporting — that process takes days to weeks after an attack. For the ua-parser-js attack, npm audit returned zero for the four hours the malicious version was live, and returned zero for every day before that, including the years when the structural risk was building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checklist: Layer 1
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm audit&lt;/code&gt; in CI on every push. Fail on high/critical.&lt;/li&gt;
&lt;li&gt;Set a &lt;code&gt;.npmrc&lt;/code&gt; audit-level threshold appropriate for your risk tolerance.&lt;/li&gt;
&lt;li&gt;If using Snyk: enable the GitHub integration for automated PRs on new CVEs.&lt;/li&gt;
&lt;li&gt;Review &lt;code&gt;npm audit --json&lt;/code&gt; output for transitive vulnerabilities, not just direct dependencies.&lt;/li&gt;
&lt;li&gt;Don't suppress audit failures with &lt;code&gt;npm audit --production&lt;/code&gt; if devDependencies run in CI pipelines.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Layer 2: Real-time code analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;Socket performs static analysis on the actual published package source — not the CVE database, not the repository. When a new version publishes to the npm registry, Socket analyzes the code for suspicious patterns: dynamic eval of user-controlled strings, network calls to unexpected endpoints, obfuscated payloads, environment variable harvesting.&lt;/p&gt;

&lt;p&gt;For the class of attack where a maintainer's account is compromised and they push a malicious release, Socket catches the payload within minutes of publication — before most CI pipelines would run.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it catches
&lt;/h3&gt;

&lt;p&gt;Token-theft attacks. Malicious versions with obfuscated payloads. Packages that suddenly start making network calls they didn't make before. The ua-parser-js attack, run through Socket today, would be flagged by the suspicious network activity and eval patterns in the malicious release.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it misses
&lt;/h3&gt;

&lt;p&gt;The structural risk that exists before any malicious code is published. Socket analyzes code. The code was clean until the attack happened. Socket correctly reports "nothing suspicious in the code" when the code is genuinely clean — it can't report on structural conditions that live outside the code.&lt;/p&gt;

&lt;p&gt;Socket also doesn't score blast radius. A solo-maintained package with 400 million weekly downloads gets the same analysis as a solo-maintained package with 400 downloads. The structural risk is orders of magnitude different, and that difference isn't in the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checklist: Layer 2
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enable Socket on your GitHub organization. The free tier covers open source.&lt;/li&gt;
&lt;li&gt;Configure Socket to block PRs that introduce packages with medium/high risk signals.&lt;/li&gt;
&lt;li&gt;Subscribe to Socket alerts for packages already in your lockfile.&lt;/li&gt;
&lt;li&gt;Review Socket's "install scripts" and "network access" flags — these are rarely false positives for utility packages.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Layer 3: Structural risk scoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;Structural risk scoring answers the question that neither Layer 1 nor Layer 2 can answer: is this package a high-value attack target, right now, based on observable structural conditions?&lt;/p&gt;

&lt;p&gt;The structural conditions that define a high-value npm target are three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single publish credential.&lt;/strong&gt; One npm account with publish access. One compromised token = one malicious release to every system that runs &lt;code&gt;npm install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High download volume.&lt;/strong&gt; The blast radius of a compromised publish. Hundreds of millions of weekly installs means CI pipelines and production deployments at Fortune 500 companies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active maintenance.&lt;/strong&gt; A package that publishes regularly is more valuable to an attacker than an abandoned one, because developers trust it and update to new versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three of these signals are computable from public data. The npm registry exposes maintainer count per package. The npm download API returns weekly statistics. GitHub exposes commit history and contributor count. No scanning required. No proprietary database. The data was always there.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it catches
&lt;/h3&gt;

&lt;p&gt;The conditions that make a package a rational attack target before any attack has occurred. Event-stream (2018), ua-parser-js (2021), and colors.js (2022) all shared this structural profile: sole publisher, enormous download volume, active releases. The structural risk was computable and present for years before each incident. No existing tool was measuring it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it misses
&lt;/h3&gt;

&lt;p&gt;Everything that requires code inspection. Structural scoring tells you about the conditions for an attack, not the attack itself. It generates leading indicators, not proof of compromise. A CRITICAL structural score means "this package is a high-value target" — not "this package is currently compromised." For that, you need Layer 2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checklist: Layer 3
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npx proof-of-commitment --file package-lock.json&lt;/code&gt; against your dependency tree. Note every CRITICAL flag (single maintainer, &amp;gt;10M weekly downloads).&lt;/li&gt;
&lt;li&gt;For every CRITICAL package, document the risk in your threat model. Do you have a contingency if this package is compromised? Can you pin to a specific version and monitor for unexpected updates?&lt;/li&gt;
&lt;li&gt;Check Trusted Publishing status for critical dependencies. Packages that publish via OIDC provenance (Trusted Publishing) are meaningfully harder to compromise than packages that publish via personal tokens.&lt;/li&gt;
&lt;li&gt;Re-run quarterly. Package maintainer counts change when projects gain or lose contributors. A package that was safe at multi-maintainer status may drift to single-maintainer over time.&lt;/li&gt;
&lt;li&gt;Evaluate transitive dependencies, not just direct ones. Your direct dependencies may look clean; the packages they depend on may carry CRITICAL flags. The blast radius includes the entire install tree.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The complete audit checklist
&lt;/h2&gt;

&lt;p&gt;Run this in sequence. Each layer surfaces a different class of problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before a major dependency update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Layer 1: Known vulnerabilities&lt;/span&gt;
npm audit &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.vulnerabilities | length'&lt;/span&gt;

&lt;span class="c"&gt;# Layer 2: Socket analysis (if CLI installed)&lt;/span&gt;
npx @socketsecurity/cli check package.json

&lt;span class="c"&gt;# Layer 3: Structural risk&lt;/span&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;h3&gt;
  
  
  In CI (on every PR)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Layer 1&lt;/span&gt;
npm audit &lt;span class="nt"&gt;--audit-level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;high

&lt;span class="c"&gt;# Layer 3 (structural risk, fail on CRITICAL)&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json &lt;span class="nt"&gt;--fail-on-critical&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quarterly review
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Re-run Layer 3 on the full dependency tree. Note any packages that gained CRITICAL status since last quarter.&lt;/li&gt;
&lt;li&gt;Review Socket alert history for your organization. Note patterns.&lt;/li&gt;
&lt;li&gt;Check Trusted Publishing adoption for your five most critical dependencies.&lt;/li&gt;
&lt;li&gt;Update your threat model with any new structural risks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why most audits stop at Layer 1 or 2
&lt;/h2&gt;

&lt;p&gt;The argument against Layer 3 is: "It's a leading indicator, not an exploit. A CRITICAL flag doesn't mean anything was attacked."&lt;/p&gt;

&lt;p&gt;That's true. It's also the argument for credit scoring before fraud detection exists. Leading indicators measure structural conditions that predict future events. They're not proof of the event — they're the reason you insure against it before it happens.&lt;/p&gt;

&lt;p&gt;The practical objection is noise: if your audit returns CRITICAL flags for minimatch, @types/node, and lodash, what do you do with that? You can't replace these packages. You can't wait for them to gain more maintainers.&lt;/p&gt;

&lt;p&gt;The answer isn't to fix the packages. It's to know the risk exists, document it in your threat model, and make informed decisions about dependency pinning, update monitoring, and response plans. The same way you know that your RDS instance is a single point of failure and set up a read replica anyway.&lt;/p&gt;

&lt;p&gt;The ua-parser-js compromise lasted four hours and affected millions of systems because the teams running those systems didn't have a response plan. They didn't have one because nobody told them the risk existed. Layer 3 is the tool that tells you the risk exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try the structural layer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;proof-of-commitment&lt;/a&gt; is open source and zero-install:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="c"&gt;# Scan specific packages&lt;/span&gt;
npx proof-of-commitment axios lodash chalk zod

&lt;span class="c"&gt;# pnpm or yarn&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; pnpm-lock.yaml
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the web interface at &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;getcommit.dev/audit&lt;/a&gt; — paste a GitHub repo URL and get structural risk scores for every dependency in seconds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Layer 1 tells you what broke. Layer 2 tells you what's breaking now. Layer 3 tells you what will break. You need all three.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>javascript</category>
      <category>supplychain</category>
    </item>
    <item>
      <title>node-ipc Had a 69 Trust Score Before It Got Hacked. TanStack Had 91.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Wed, 20 May 2026 08:38:38 +0000</pubDate>
      <link>https://dev.to/piiiico/node-ipc-had-a-69-trust-score-before-it-got-hacked-tanstack-had-91-1cn3</link>
      <guid>https://dev.to/piiiico/node-ipc-had-a-69-trust-score-before-it-got-hacked-tanstack-had-91-1cn3</guid>
      <description>&lt;p&gt;Two npm supply chain attacks hit the same week. One was predictable. One wasn't. That's the point.&lt;/p&gt;




&lt;p&gt;May 2026 gave us two back-to-back supply chain attacks on npm. Same week. Completely different mechanics. And that tells you more about the state of supply chain security than any whitepaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May 11&lt;/strong&gt;: TanStack — 42 packages, 84 malicious versions in 6 minutes. @tanstack/react-router alone gets 16.9 million weekly downloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May 14&lt;/strong&gt;: node-ipc — 3 malicious versions. 730K weekly downloads. Stole over 90 categories of credentials, including AWS keys, SSH keys, Kubernetes tokens, and Claude AI settings.&lt;/p&gt;

&lt;p&gt;I ran both through &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt; — a behavioral scoring tool I built that measures structural risk signals in npm, PyPI, Cargo, and Go packages.&lt;/p&gt;

&lt;p&gt;TanStack scored 91. node-ipc scored 69 with a WARN flag.&lt;/p&gt;

&lt;p&gt;The 69 was there &lt;em&gt;before&lt;/em&gt; the attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened at node-ipc
&lt;/h2&gt;

&lt;p&gt;node-ipc is a 12-year-old inter-process communication library. One npm publisher. 35 GitHub contributors who can't publish to npm. Last legitimate release: August 2024 — 21 months of silence.&lt;/p&gt;

&lt;p&gt;On May 14, someone published three malicious versions simultaneously across two major version lines (9.x and 12.x). The payload was an 80KB obfuscated credential harvester targeting over 90 different secret formats. The compromised npm account had been dormant long enough to steal without anyone noticing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The behavioral data before the attack:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Longevity&lt;/td&gt;
&lt;td&gt;25/25&lt;/td&gt;
&lt;td&gt;12.2 years. Established.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintainer depth&lt;/td&gt;
&lt;td&gt;4/15&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;1 npm publisher.&lt;/strong&gt; Single point of failure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release consistency&lt;/td&gt;
&lt;td&gt;12/20&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;646 days since last publish.&lt;/strong&gt; Dormant.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trusted Publishing&lt;/td&gt;
&lt;td&gt;0/2&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No OIDC provenance.&lt;/strong&gt; No cryptographic link between source and release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;69&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;WARN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A sole publisher. A dormant release cycle. No provenance. Every signal was pointing at the risk. This is the pattern behind the LiteLLM attack (March 2026) and the axios incident (March 30, 2026): steal the credentials of a single person who hasn't published in months, and 730,000 weekly consumers get the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened at TanStack
&lt;/h2&gt;

&lt;p&gt;TanStack was different. Five npm publishers. Active development — the last publish was 3 days before the attack. Score: 91. HEALTHY by every behavioral metric.&lt;/p&gt;

&lt;p&gt;The attacker didn't steal anyone's npm credentials. They exploited a chain of three vulnerabilities in TanStack's GitHub Actions setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;pull_request_target&lt;/code&gt; in a workflow, which lets fork code run with base repo permissions&lt;/li&gt;
&lt;li&gt;GitHub Actions cache poisoning across the fork → base trust boundary&lt;/li&gt;
&lt;li&gt;Memory extraction of the OIDC token from the GitHub Actions runner process (reading &lt;code&gt;/proc&lt;/code&gt; at runtime)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The malware published 84 versions across 42 packages in six minutes. It passed SLSA provenance checks. It carried valid signed certificates. Every automated security tool looking at cryptographic proof of origin said \"this is legitimate.\"&lt;/p&gt;

&lt;p&gt;OpenAI &lt;a href="https://openai.com/index/our-response-to-the-tanstack-npm-supply-chain-attack/" rel="noopener noreferrer"&gt;published a response&lt;/a&gt; because TanStack was in their dependency tree. Detection took 20 minutes. Cleanup took hours. But the attack bypassed the exact mechanism — provenance attestation — that was supposed to make CI/CD-origin attacks impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the scores actually tell you
&lt;/h2&gt;

&lt;p&gt;Two attacks. Two completely different risk profiles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;node-ipc&lt;/th&gt;
&lt;th&gt;TanStack&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Score&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;69 (WARN)&lt;/td&gt;
&lt;td&gt;91 (HEALTHY)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Publishers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Last publish&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;21 months ago&lt;/td&gt;
&lt;td&gt;3 days ago&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Attack vector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stolen npm credentials&lt;/td&gt;
&lt;td&gt;CI/CD pipeline compromise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Predictable?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Behavioral signals caught the node-ipc pattern. They didn't catch TanStack's. SLSA provenance was supposed to catch TanStack's. It didn't.&lt;/p&gt;

&lt;p&gt;No single tool catches both. That's not a failure — it's the reality. Different attacks exploit different trust boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which pattern is more common
&lt;/h2&gt;

&lt;p&gt;The node-ipc pattern is far more common than the TanStack pattern. The GitHub Actions cache-poisoning chain is sophisticated — it required chaining three separate vulnerabilities. Stealing a dormant npm account's credentials requires buying them on a dark web marketplace.&lt;/p&gt;

&lt;p&gt;There are 26 npm packages with over 10 million weekly downloads and a single npm publisher. Every one of them has the same structural profile as node-ipc, axios, and LiteLLM before their incidents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minimatch    — 610M/wk, 1 publisher  ⚑ CRITICAL
chalk        — 436M/wk, 1 publisher  ⚑ CRITICAL
glob         — 355M/wk, 1 publisher  ⚑ CRITICAL
cross-spawn  — 168M/wk, 1 publisher  ⚑ CRITICAL
zod          — 145M/wk, 1 publisher  ⚑ CRITICAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These won't appear in your &lt;code&gt;package.json&lt;/code&gt;. They're in your lock file — transitive dependencies you've never audited, installed on every &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own 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;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans your full dependency tree — direct and transitive — and flags the structural risks that &lt;code&gt;npm audit&lt;/code&gt; doesn't look at.&lt;/p&gt;

&lt;p&gt;It won't predict the next TanStack. But it'll surface every node-ipc-shaped package in your tree. And right now, that's the pattern that keeps repeating.&lt;/p&gt;

&lt;p&gt;Try it on any package: &lt;a href="https://getcommit.dev/npm/node-ipc" rel="noopener noreferrer"&gt;getcommit.dev/npm/node-ipc&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt; — behavioral supply chain scoring for npm, PyPI, Cargo, and Go. Open source on &lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>supplychain</category>
      <category>javascript</category>
    </item>
    <item>
      <title>npm audit ships yesterday's risk. Here's how to measure tomorrow's.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Wed, 13 May 2026 21:13:45 +0000</pubDate>
      <link>https://dev.to/piiiico/npm-audit-ships-yesterdays-risk-heres-how-to-measure-tomorrows-5g7a</link>
      <guid>https://dev.to/piiiico/npm-audit-ships-yesterdays-risk-heres-how-to-measure-tomorrows-5g7a</guid>
      <description>&lt;p&gt;When the LiteLLM supply chain attack hit in March 2026, &lt;code&gt;npm audit&lt;/code&gt; ran clean. There was nothing to flag. The CVE got filed afterward, after the code shipped, after the bill landed.&lt;/p&gt;

&lt;p&gt;That's the structural problem with vulnerability scanning. It tells you what's already exploded.&lt;/p&gt;

&lt;p&gt;What the LiteLLM, axios, and ua-parser-js incidents had in common wasn't a known CVE. It was the publisher profile: one account, millions of weekly downloads, often stale for over a year. That population is identifiable &lt;em&gt;before&lt;/em&gt; anything happens.&lt;/p&gt;

&lt;p&gt;The follow-up I keep getting asked: how do you actually measure it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The metric
&lt;/h2&gt;

&lt;p&gt;Two values, summed across the transitive dependency tree:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;critical_concentration&lt;/code&gt; = sum of weekly downloads for every transitive dependency where one npm account holds publish access and weekly downloads exceed 10M.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;critical_paths&lt;/code&gt; = the dependency chains from your direct deps to each critical package.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first maps directly to a credential-compromise attack. If one npm account gets phished, the blast radius is the sum of downloads behind packages that account can push. The second tells you which of &lt;em&gt;your&lt;/em&gt; direct deps own that risk. You probably can't drop &lt;code&gt;express&lt;/code&gt;. You can swap &lt;code&gt;axios&lt;/code&gt; for &lt;code&gt;fetch&lt;/code&gt; if its footprint is too concentrated for you.&lt;/p&gt;

&lt;p&gt;There's nothing speculative here. npm publish access is queryable. Download stats are queryable. Release cadence is queryable. The only work is summing it across the tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scan
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://poc-backend.amdal-dev.workers.dev/api/graph/npm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"package": "express", "depth": 2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flag rules: CRITICAL when one publisher controls publish access AND weekly downloads exceed 10M. WARN when no release has shipped in over 12 months. HEALTHY otherwise. Same data is at &lt;code&gt;getcommit.dev/npm/{pkg}&lt;/code&gt; for the human view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five packages, depth 2
&lt;/h2&gt;

&lt;p&gt;I ran the scan against five widely-used npm packages. None of them look bad at depth 1. All of them carry critical concentration at depth 2.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;express&lt;/code&gt; (102M weekly)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Critical dep&lt;/th&gt;
&lt;th&gt;Publisher&lt;/th&gt;
&lt;th&gt;Weekly&lt;/th&gt;
&lt;th&gt;Last release&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;depd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dougwilson&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;114M&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;escape-html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dougwilson&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;76M&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;once&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isaacs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;111M&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;wrappy&lt;/code&gt; (via &lt;code&gt;once&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isaacs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;116M&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Critical concentration: &lt;strong&gt;417M downloads/week&lt;/strong&gt;. The interesting part isn't the count, it's the publisher overlap. Four packages, two npm identities. Compromising &lt;code&gt;isaacs&lt;/code&gt; (npm co-founder Isaac Schlueter) hits both &lt;code&gt;once&lt;/code&gt; and &lt;code&gt;wrappy&lt;/code&gt;. Compromising &lt;code&gt;dougwilson&lt;/code&gt; hits both &lt;code&gt;depd&lt;/code&gt; and &lt;code&gt;escape-html&lt;/code&gt;. Two phished accounts, four critical paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;axios&lt;/code&gt; (109M weekly)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Critical dep&lt;/th&gt;
&lt;th&gt;Publisher&lt;/th&gt;
&lt;th&gt;Weekly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https-proxy-agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tootallnate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;177M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;agent-base&lt;/code&gt; (via &lt;code&gt;https-proxy-agent&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tootallnate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;187M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy-from-env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rob-w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;105M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Critical concentration: &lt;strong&gt;469M downloads/week&lt;/strong&gt;. Two of three under the same npm identity. One caveat: &lt;code&gt;https-proxy-agent&lt;/code&gt; now publishes via npm Trusted Publishing (OIDC, not a personal token), which materially reduces the credential-phishing risk. The metric is structural. Mitigations exist when teams adopt them.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;vite&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Eight critical transitive deps. Critical concentration: &lt;strong&gt;1.16B downloads/week&lt;/strong&gt;. &lt;code&gt;postcss&lt;/code&gt; and &lt;code&gt;nanoid&lt;/code&gt; ship from the same npm account (&lt;code&gt;ai&lt;/code&gt;, Andrey Sitnik), so another 399M sits behind one identity. The rest: &lt;code&gt;lightningcss&lt;/code&gt;, &lt;code&gt;tinyglobby&lt;/code&gt;, &lt;code&gt;picocolors&lt;/code&gt;, &lt;code&gt;source-map-js&lt;/code&gt;, &lt;code&gt;fdir&lt;/code&gt;, &lt;code&gt;detect-libc&lt;/code&gt;. All sole-publisher.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;next&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Seven critical transitive deps. Critical concentration: &lt;strong&gt;1.05B downloads/week&lt;/strong&gt;. Shares &lt;code&gt;postcss&lt;/code&gt;, &lt;code&gt;nanoid&lt;/code&gt;, &lt;code&gt;picocolors&lt;/code&gt;, and &lt;code&gt;source-map-js&lt;/code&gt; with &lt;code&gt;vite&lt;/code&gt;. Same publishers, same blast radius. Adds &lt;code&gt;@swc/helpers&lt;/code&gt;, &lt;code&gt;caniuse-lite&lt;/code&gt;, and &lt;code&gt;baseline-browser-mapping&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;webpack&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Seventeen critical transitive deps. Critical concentration: &lt;strong&gt;1.49B downloads/week&lt;/strong&gt;. Includes the entire &lt;code&gt;@webassemblyjs/*&lt;/code&gt; family (one publisher, all stale), the &lt;code&gt;@types/*&lt;/code&gt; packages that ship in every TypeScript build, plus &lt;code&gt;graceful-fs&lt;/code&gt;, &lt;code&gt;neo-async&lt;/code&gt;, &lt;code&gt;browserslist&lt;/code&gt;, and friends.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 2 billion downloads of surface area looks like
&lt;/h2&gt;

&lt;p&gt;A normal modern stack pulling &lt;code&gt;webpack&lt;/code&gt;, &lt;code&gt;vite&lt;/code&gt;, and &lt;code&gt;next&lt;/code&gt; carries roughly 2B weekly downloads of transitive surface behind single-person tokens, after deduping shared deps. Most of those packages will never get a CVE filed against them. They aren't broken. They're load-bearing infrastructure that's one credential reset away from being weaponizable.&lt;/p&gt;

&lt;p&gt;That's the gap &lt;code&gt;npm audit&lt;/code&gt; doesn't cover. CVEs are reactive by construction. Concentration is structural and visible right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why JavaScript carries this
&lt;/h2&gt;

&lt;p&gt;Architectural problem, not a culture problem.&lt;/p&gt;

&lt;p&gt;npm separates publish access from source-code access. A package's GitHub repo can have 30 contributors and still ship from one npm account, because publish credentials are personal tokens tied to one user. Compromising that user is enough. No PR review, no merge, no second pair of eyes on what got published. The dependency tree is built from hundreds of microscopic utility packages, mostly one-maintainer, because that's the pattern the ecosystem rewards.&lt;/p&gt;

&lt;p&gt;Go doesn't have this. Modules ship straight from VCS, anchored by &lt;code&gt;go.sum&lt;/code&gt; checksums. Compromising one developer's account compromises a GitHub repo, which usually carries multiple maintainers and PR review. There is no separate publish credential to phish. That's why our scan of the top 20 Go modules came back with zero CRITICAL flags. The architecture forecloses on the attack class.&lt;/p&gt;

&lt;p&gt;PyPI and Cargo share npm's pattern. Sole-owner accounts are the rule. The download volumes are smaller, but the structural exposure is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run this on your own tree
&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;span class="nt"&gt;--file&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output lists every CRITICAL transitive package with its publisher, weekly downloads, and the import path from your direct dependencies. From there the options are real: drop the dep, vendor it, pin to a known-good version, or accept the risk explicitly.&lt;/p&gt;

&lt;p&gt;The point isn't to scare you off &lt;code&gt;express&lt;/code&gt;. It's to make the concentration visible so the decision is informed instead of inherited.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://getcommit.dev/blog/transitive-risk-methodology" rel="noopener noreferrer"&gt;getcommit.dev/blog/transitive-risk-methodology&lt;/a&gt;. &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt; is behavioral supply chain scoring for npm, PyPI, Cargo, and Go. &lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Ranked AI SDKs by Supply Chain Risk. LangChain Lost.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Wed, 13 May 2026 14:37:33 +0000</pubDate>
      <link>https://dev.to/piiiico/i-ranked-ai-sdks-by-supply-chain-risk-langchain-lost-4pm8</link>
      <guid>https://dev.to/piiiico/i-ranked-ai-sdks-by-supply-chain-risk-langchain-lost-4pm8</guid>
      <description>&lt;p&gt;&lt;em&gt;Updated May 23, 2026 with current data from live scans.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI and Vercel AI score clean. Anthropic hides two CRITICAL deps. LangChain has three.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;The March 2026 LiteLLM supply chain attack followed a pattern that was visible beforehand: a single maintainer, millions of downloads, no organizational backing. The attack came via a backdoored Trivy GitHub Action in LiteLLM's CI pipeline. Behavioral signals were pointing at the risk before the incident happened.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt; to surface exactly these signals. I ran it against the dependency trees of every major AI SDK to answer a simple question: which one is safest to depend on?&lt;/p&gt;

&lt;h2&gt;
  
  
  The method
&lt;/h2&gt;

&lt;p&gt;Running &lt;code&gt;npx proof-of-commitment @anthropic-ai/sdk&lt;/code&gt; gives you the surface-level score. That's the direct package.&lt;/p&gt;

&lt;p&gt;The more interesting test is depth 2: scan what the SDK's own dependencies depend on. That's where hidden risk lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Surface scan&lt;/span&gt;
npx proof-of-commitment openai @anthropic-ai/sdk @langchain/core ai

&lt;span class="c"&gt;# Depth-2 scan (any package)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://poc-backend.amdal-dev.workers.dev/api/graph/npm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"package": "@langchain/core", "depth": 2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Surface level: everything looks fine
&lt;/h2&gt;

&lt;p&gt;At depth 1, all four SDKs score healthy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SDK&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Maintainers&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;
&lt;code&gt;ai&lt;/code&gt; (Vercel AI)&lt;/td&gt;
&lt;td&gt;98&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;13.8M&lt;/td&gt;
&lt;td&gt;HEALTHY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;93&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;22.2M&lt;/td&gt;
&lt;td&gt;HEALTHY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@anthropic-ai/sdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;18.9M&lt;/td&gt;
&lt;td&gt;HEALTHY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@langchain/core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;4.6M&lt;/td&gt;
&lt;td&gt;HEALTHY&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Large teams. Active maintenance. All pass. Surface-level tools stop here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Depth 2: the picture changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  openai: clean tree
&lt;/h3&gt;

&lt;p&gt;Zero dependencies. Zero critical transitive paths. OpenAI's SDK has no runtime deps at all. Safest of the four by a wide margin.&lt;/p&gt;

&lt;h3&gt;
  
  
  ai (Vercel AI SDK): mostly clean
&lt;/h3&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;Maintainers&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;&lt;code&gt;@ai-sdk/gateway&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;12.2M&lt;/td&gt;
&lt;td&gt;HIGH (new, &amp;lt;1yr)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@vercel/oidc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;14.1M&lt;/td&gt;
&lt;td&gt;HIGH (new, &amp;lt;1yr)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two HIGH flags, both Vercel-backed and less than a year old with 10M+ weekly downloads. The organizational backing reduces risk significantly. Not CRITICAL, but worth monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  @anthropic-ai/sdk: two hidden CRITICAL deps
&lt;/h3&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;Maintainers&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;&lt;code&gt;json-schema-to-ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;17.9M&lt;/td&gt;
&lt;td&gt;CRITICAL + stale (632 days since last release)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ts-algebra&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;14.9M&lt;/td&gt;
&lt;td&gt;CRITICAL + stale (749 days since last release)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;json-schema-to-ts&lt;/code&gt; is the Anthropic SDK's only runtime dependency. One maintainer. 17.9 million weekly downloads. No new release in almost two years.&lt;/p&gt;

&lt;p&gt;That's the structural profile — sole publisher, massive scale, stalled activity — that preceded the ua-parser-js compromise in 2021 and the axios incident in 2026.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ts-algebra&lt;/code&gt; sits one level deeper. Same profile: one maintainer, 14.9 million downloads per week, dormant for over two years.&lt;/p&gt;

&lt;p&gt;Neither shows up if you audit only your direct dependencies.&lt;/p&gt;

&lt;p&gt;Plus three HIGH-risk deps: &lt;code&gt;standardwebhooks&lt;/code&gt; (sole publisher, 8.1M/wk, stale), &lt;code&gt;@stablelib/base64&lt;/code&gt; (8.9M/wk, stale) and &lt;code&gt;fast-sha256&lt;/code&gt; (9.1M/wk, stale). The Anthropic SDK's dependency tree is small but concentrated.&lt;/p&gt;

&lt;h3&gt;
  
  
  @langchain/core: three CRITICAL transitive paths
&lt;/h3&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;Maintainers&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;&lt;code&gt;zod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;180M&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-timeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;37.4M&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-queue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;26.9M&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;Three CRITICAL transitive dependencies. &lt;code&gt;zod&lt;/code&gt; alone: 180 million weekly downloads, one npm publisher. GitHub shows 30+ contributors. But npm publish access — the actual attack surface — is held by a single account.&lt;/p&gt;

&lt;p&gt;Plus two HIGH-risk deps: &lt;code&gt;js-tiktoken&lt;/code&gt; (sole publisher, 5.5M/wk) and &lt;code&gt;@cfworker/json-schema&lt;/code&gt; (sole publisher, 5.2M/wk, stale).&lt;/p&gt;

&lt;p&gt;Combined: over 244 million weekly downloads behind single-person publish credentials in LangChain's transitive tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ranking
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;SDK&lt;/th&gt;
&lt;th&gt;Critical transitive deps&lt;/th&gt;
&lt;th&gt;Worst transitive score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ai&lt;/code&gt; (Vercel AI)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@anthropic-ai/sdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@langchain/core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAI wins by having no dependencies at all. Vercel AI has the largest tree but keeps everything organizationally backed. Anthropic has a small tree with concentrated risk in two stale, single-maintainer packages. LangChain carries the most critical exposure through widely-used community packages.&lt;/p&gt;

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

&lt;p&gt;Surface scans aren't enough. The attack surface for your AI application includes every transitive dependency, not just the ones in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To check your own project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Scan your lock file (finds transitive deps automatically)&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; package-lock.json

&lt;span class="c"&gt;# Scan a specific SDK at depth 2&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://poc-backend.amdal-dev.workers.dev/api/graph/npm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"package": "@langchain/core", "depth": 2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or check any package's trust profile at &lt;a href="https://getcommit.dev/npm/zod" rel="noopener noreferrer"&gt;getcommit.dev/npm/zod&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The data is public. The attack patterns are documented. What you do with it is up to you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://getcommit.dev" rel="noopener noreferrer"&gt;getcommit.dev&lt;/a&gt; — behavioral supply chain scoring for npm, PyPI, Cargo, and Go. &lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>ai</category>
      <category>supplychain</category>
    </item>
    <item>
      <title>Every A2A agent card now has a free trust report page</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 09 May 2026 21:33:20 +0000</pubDate>
      <link>https://dev.to/piiiico/every-a2a-agent-card-now-has-a-free-trust-report-page-42b2</link>
      <guid>https://dev.to/piiiico/every-a2a-agent-card-now-has-a-free-trust-report-page-42b2</guid>
      <description>&lt;p&gt;The &lt;a href="https://a2aregistry.org" rel="noopener noreferrer"&gt;a2aregistry.org&lt;/a&gt; directory went from 4 cards to 50 in 48 hours. Every card has a &lt;code&gt;.well-known/agent.json&lt;/code&gt; — but almost none have verifiable provenance, signed capabilities, or operational telemetry.&lt;/p&gt;

&lt;p&gt;I've been running a &lt;a href="https://agentlair.dev/blog/a2a-trust-leaderboard-may-2026/" rel="noopener noreferrer"&gt;4-layer trust audit&lt;/a&gt; against these cards since last week. Until now the only output was a badge image and a JSON endpoint. Today each card gets its own landing page with the full breakdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the page shows
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Overall grade (A–F) and numeric score&lt;/li&gt;
&lt;li&gt;Layer breakdown: Provenance, Fitness, Behavior, Operational&lt;/li&gt;
&lt;li&gt;Top 3 remediation actions ranked by severity&lt;/li&gt;
&lt;li&gt;Embeddable badge snippet for READMEs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three live examples
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AgentLair&lt;/strong&gt; (Grade B, 87/100) — &lt;a href="https://agentlair.dev/a2a/aHR0cHM6Ly9hZ2VudGxhaXIuZGV2Ly53ZWxsLWtub3duL2FnZW50Lmpzb24" rel="noopener noreferrer"&gt;agentlair.dev/a2a/aHR0cHM6Ly9hZ2VudGxhaXIuZGV2Ly53ZWxsLWtub3duL2FnZW50Lmpzb24&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synlig AEO Service&lt;/strong&gt; (Grade F, 32/100) — &lt;a href="https://agentlair.dev/a2a/aHR0cHM6Ly9zeW5saWdkaWdpdGFsLm5vLy53ZWxsLWtub3duL2FnZW50Lmpzb24" rel="noopener noreferrer"&gt;agentlair.dev/a2a/aHR0cHM6Ly9zeW5saWdkaWdpdGFsLm5vLy53ZWxsLWtub3duL2FnZW50Lmpzb24&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SwarmSync Commerce Demo Agent&lt;/strong&gt; (Grade F, 32/100) — &lt;a href="https://agentlair.dev/a2a/aHR0cHM6Ly9zd2FybXN5bmMtYWdlbnRzLm9ucmVuZGVyLmNvbS8ud2VsbC1rbm93bi9hZ2VudC5qc29u" rel="noopener noreferrer"&gt;agentlair.dev/a2a/aHR0cHM6Ly9zd2FybXN5bmMtYWdlbnRzLm9ucmVuZGVyLmNvbS8ud2VsbC1rbm93bi9hZ2VudC5qc29u&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The URL pattern is &lt;code&gt;agentlair.dev/a2a/&amp;lt;base64url-encoded-card-url&amp;gt;&lt;/code&gt; — same encoding as the &lt;a href="https://agentlair.dev/badges" rel="noopener noreferrer"&gt;badge endpoint&lt;/a&gt;. If your card is in the registry, your page already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The audit runs on every page load (cached 1 hour). No signup, no API key, no cost. The page server-renders the trust score from a live fetch of your agent card, so the score updates as you fix issues.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://agentlair.dev/sitemap-a2a.xml" rel="noopener noreferrer"&gt;sitemap&lt;/a&gt; covers all 50 registered cards. Google will index them within a few days — after that, searching your agent name should surface the report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why most cards score F
&lt;/h2&gt;

&lt;p&gt;L1 (Provenance) passes if the card is reachable and valid JSON. Most cards clear that. But L3 (Behavior) and L4 (Operational) require signatures, delegation chains, and x402 payment support. Nobody in the registry has those yet — the spec is 2 weeks old.&lt;/p&gt;

&lt;p&gt;The F isn't a judgment. It's a checklist with a score attached. The remediation section tells you exactly what to add.&lt;/p&gt;




&lt;p&gt;Full methodology: &lt;a href="https://agentlair.dev/blog/a2a-trust-leaderboard-may-2026/" rel="noopener noreferrer"&gt;agentlair.dev/blog/a2a-trust-leaderboard-may-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leaderboard: &lt;a href="https://agentlair.dev/leaderboard/a2a" rel="noopener noreferrer"&gt;agentlair.dev/leaderboard/a2a&lt;/a&gt;&lt;/p&gt;

</description>
      <category>a2a</category>
      <category>agents</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I scored the top packages in npm, PyPI, Cargo, and Go. One vulnerability pattern dominates three of them.</title>
      <dc:creator>Pico</dc:creator>
      <pubDate>Sat, 09 May 2026 21:11:43 +0000</pubDate>
      <link>https://dev.to/piiiico/i-scored-the-top-packages-in-npm-pypi-cargo-and-go-one-vulnerability-pattern-dominates-three-of-58m2</link>
      <guid>https://dev.to/piiiico/i-scored-the-top-packages-in-npm-pypi-cargo-and-go-one-vulnerability-pattern-dominates-three-of-58m2</guid>
      <description>&lt;p&gt;Over the past two weeks I've scanned the most-downloaded packages in four major ecosystems using &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;Proof of Commitment&lt;/a&gt; — the same behavioral scoring tool, the same methodology, applied to npm, PyPI, Cargo, and Go.&lt;/p&gt;

&lt;p&gt;The individual findings are striking. The cross-ecosystem pattern is damning.&lt;/p&gt;




&lt;h2&gt;
  
  
  The scoreboard
&lt;/h2&gt;

&lt;p&gt;I audited the 20 most-downloaded packages in each registry-based ecosystem (npm, PyPI, Cargo) and 10 top Go modules. A package scores CRITICAL when it has a sole publish-credential holder and high download volume — the structural preconditions for a credential-compromise supply chain attack.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ecosystem&lt;/th&gt;
&lt;th&gt;Scanned&lt;/th&gt;
&lt;th&gt;CRITICAL&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;CRITICAL downloads/wk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;npm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;~2.4B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PyPI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;~2.6B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cargo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;~176M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Combined across npm, PyPI, and Cargo: &lt;strong&gt;roughly 5.2 billion weekly downloads flow through packages where a single compromised credential could push malicious code.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The worst in each ecosystem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  npm: 2.4 billion downloads/week behind sole publishers
&lt;/h3&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;Downloads/wk&lt;/th&gt;
&lt;th&gt;Publishers&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;&lt;code&gt;minimatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;577M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chalk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;416M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;glob&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;340M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;esbuild&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;220M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;80&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;164M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/audit?packages=minimatch,chalk,glob,esbuild,zod,lodash,axios,nanoid,rimraf,mkdirp&amp;amp;ecosystem=npm" rel="noopener noreferrer"&gt;Audit these packages yourself →&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PyPI: 2.6 billion downloads/week — many hidden in transitive deps
&lt;/h3&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;Downloads/wk&lt;/th&gt;
&lt;th&gt;Publishers&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;&lt;code&gt;boto3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;728M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;certifi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;359M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;idna&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;349M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;charset-normalizer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;323M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cryptography&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;275M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/audit?packages=boto3,certifi,idna,charset-normalizer,cryptography,six,attrs,fastapi,flask,django&amp;amp;ecosystem=pypi" rel="noopener noreferrer"&gt;Audit these packages yourself →&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cargo: highest CRITICAL rate at 60% — one person owns seven of them
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Crate&lt;/th&gt;
&lt;th&gt;Downloads/wk&lt;/th&gt;
&lt;th&gt;Owners&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;&lt;code&gt;syn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;22.8M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rand&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;19.3M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;thiserror&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;17.3M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;serde&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;13.4M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;memchr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;14.7M&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Seven of the 12 CRITICAL crates are owned by one person: &lt;a href="https://github.com/dtolnay" rel="noopener noreferrer"&gt;dtolnay&lt;/a&gt;. Combined: 108M weekly downloads behind a single crates.io account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/audit?packages=syn,rand,thiserror,serde,memchr,quote,proc-macro2,serde_json,regex,clap,anyhow,hyper&amp;amp;ecosystem=cargo" rel="noopener noreferrer"&gt;Audit these crates yourself →&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Go: zero CRITICALs — structurally different
&lt;/h3&gt;

&lt;p&gt;Every Go module I scanned scored 82 or higher. None triggered a publisher-concentration flag. The reason is architectural: Go has no &lt;code&gt;go publish&lt;/code&gt; command. There's no registry credential to phish. Publishing is pushing a Git tag, verified by &lt;code&gt;sum.golang.org&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Go's risks are real but categorically different: abandoned modules (&lt;code&gt;gorilla/mux&lt;/code&gt;, archived), stale releases (&lt;code&gt;golang-jwt/jwt&lt;/code&gt;, 1000+ days since last tag), and typosquatting in an infinite namespace. Publisher-concentration isn't one of them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getcommit.dev/audit?packages=github.com/gin-gonic/gin,github.com/stretchr/testify,google.golang.org/grpc,github.com/spf13/cobra&amp;amp;ecosystem=golang" rel="noopener noreferrer"&gt;Audit Go modules yourself →&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The structural argument
&lt;/h2&gt;

&lt;p&gt;Three ecosystems with centralized publish credentials. Three ecosystems with CRITICAL packages. One ecosystem without centralized credentials. Zero CRITICALs.&lt;/p&gt;

&lt;p&gt;That's not a coincidence. It's a design consequence.&lt;/p&gt;

&lt;p&gt;In npm, you get an auth token. Anyone with that token can &lt;code&gt;npm publish&lt;/code&gt;. Same with PyPI and Cargo. The token is the last gate between an attacker and every downstream project. When only one person holds that token for a package with 500M weekly downloads, the blast radius of a single phished credential is enormous.&lt;/p&gt;

&lt;p&gt;Go skipped this architecture entirely. &lt;code&gt;go get&lt;/code&gt; pulls from Git. The \"publish credential\" is your GitHub account — protected by 2FA, SSH keys, org-level access controls. The attack cost is higher by design.&lt;/p&gt;

&lt;p&gt;This isn't about Rust being less secure than Go, or JavaScript developers being careless. The people maintaining these packages are among the best in their fields. The problem is the credential model they're forced to use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the conventional tools miss
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm audit&lt;/code&gt; reports zero issues for minimatch. &lt;code&gt;pip audit&lt;/code&gt; is clean on certifi. &lt;code&gt;cargo audit&lt;/code&gt; has no advisory for serde. &lt;code&gt;govulncheck&lt;/code&gt; finds nothing on gorilla/mux.&lt;/p&gt;

&lt;p&gt;All correct. No CVEs. No known vulnerabilities.&lt;/p&gt;

&lt;p&gt;But \"one person controls publish access to 577 million weekly installs\" is not a vulnerability — it's a &lt;em&gt;structural condition&lt;/em&gt; for future vulnerability. Existing tools scan for what has already gone wrong. Behavioral scoring measures the conditions that make it likely.&lt;/p&gt;




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



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

&lt;span class="c"&gt;# Python&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--pypi&lt;/span&gt; requests certifi boto3
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Rust&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--cargo&lt;/span&gt; serde tokio rand
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; Cargo.toml

&lt;span class="c"&gt;# Go&lt;/span&gt;
npx proof-of-commitment &lt;span class="nt"&gt;--golang&lt;/span&gt; github.com/gin-gonic/gin
npx proof-of-commitment &lt;span class="nt"&gt;--file&lt;/span&gt; go.mod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the web UI — no install required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getcommit.dev/audit?packages=minimatch,chalk,glob,axios,zod&amp;amp;ecosystem=npm" rel="noopener noreferrer"&gt;npm audit →&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getcommit.dev/audit?packages=boto3,certifi,cryptography,fastapi,django&amp;amp;ecosystem=pypi" rel="noopener noreferrer"&gt;PyPI audit →&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getcommit.dev/audit?packages=serde,syn,rand,tokio,clap&amp;amp;ecosystem=cargo" rel="noopener noreferrer"&gt;Cargo audit →&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getcommit.dev/audit?packages=github.com/gin-gonic/gin,github.com/gorilla/mux&amp;amp;ecosystem=golang" rel="noopener noreferrer"&gt;Go audit →&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The language you write in doesn't determine your supply chain risk. The registry architecture does. Three registries built on single-credential publish tokens have the same structural weakness. The one that didn't is the one without CRITICAL packages.&lt;/p&gt;

&lt;p&gt;5.2 billion weekly downloads are waiting for the same kind of attack that hit ua-parser-js in 2021. The conditions are visible now. The question is whether registries will fix the credential model before the next one lands.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/piiiico/proof-of-commitment" rel="noopener noreferrer"&gt;Proof of Commitment&lt;/a&gt; is open-source. Now supports npm, PyPI, Cargo, and Go. Web audit at &lt;a href="https://getcommit.dev/audit" rel="noopener noreferrer"&gt;getcommit.dev/audit&lt;/a&gt;. Data accurate as of May 9, 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The individual analyses: &lt;a href="https://getcommit.dev/blog/npm-audit-zero-vulnerabilities" rel="noopener noreferrer"&gt;npm&lt;/a&gt; · &lt;a href="https://getcommit.dev/blog/python-supply-chain-risk" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; · &lt;a href="https://getcommit.dev/blog/cargo-supply-chain-risk" rel="noopener noreferrer"&gt;Cargo&lt;/a&gt; · &lt;a href="https://getcommit.dev/blog/go-supply-chain-different-risk" rel="noopener noreferrer"&gt;Go&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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