npm で発生した “依存性地獄”:パッケージ削除を禁止する最悪の連鎖が発生

‘everything’ blocks devs from removing their own npm packages

2024/01/04 BleepingComputer — 年末年始の連休中に、npm パッケージのレジストリは 3,000以上のパッケージで溢れかえった。この、”everything” をダウンロードするように命名されたパッケージは、すべての npm パッケージを徐々に取り込む。それらは、コンピュータ上の npmjs.com レジストリに公開されものであり、ストレージが不足する可能性がある。 しかし、このような問題は、氷山の一角にすぎない。つまり、誰が “everything をインストールするのかという疑問は、このパッケージが持っている、もっと大きな副作用を無視している。

これらの 3,000以上のパッケージは、npmjs.com レジストリにある全ての npm パッケージとの依存関係を取り込んでいるため、npm レジストリにパッケージを公開したことのある作者は、npm のポリシーにより、自分のパッケージを自由に削除できなくなるのだ。

パッケージのアンパブリッシュを妨げるすべてのもの

この問題は、単純ないたずらとして始まったかもしれないが、結果として npm エコシステム全体の作者に対して、大きな影響を与えることになった。

この “everything” をインストールすることで、あなたのコンピュータのストレージ容量が不足し、動作が遅くなる可能性があるかもしれない。しかし、この悪意のパッケージが npmjs.com に存在するだけで、このパッケージとは全く関係のない作者が、世界最大の JavaScript ソフトウェア・レジストリから、自身のパッケージをアンパブリッシュできなくなってしまうのだ。

この “everything” パッケージには、”@everything-registry” スコープで公開されている、5つのサブパッケージが依存関係としてリストアップされているだけだと、BleepingComputer は観測している。

npm package called "everything" attempts to install every package on the npm registry
“everything” and its many dependencies fetch every single npm package from the registry
(BleepingComputer)

しかし、これら5つのパッケージは、レジストリ全体に存在する全てのパッケージを、依存関係として徐々に取り込んでいく。たとえば、”everything” は “@everything-registry/chunk-2″ を取り込んだ後に、”@everything-registry/sub-chunk-1623” のような、同じ作者による他のパッケージも取り込もうとする。

これらのサブ・パッケージ (chunk) は、それぞれが、最終的に約 800 の npm プロジェクトを依存関係として取り込んでいる。

3000+ packages that pull in everything from the npmjs.com registry
3000+ packages that pull in everything from the npmjs.com registry

“everything” の作者が、3,000以上ものパッケージ (chunk) を公開し、それぞれが数百の依存関係を持つことを考えると、単一のnpm install everythingコマンドは、いわゆる推移的な依存関係を解決し始め、最終的に数百万のパッケージをダウンロードすることになる。

この悪ふざけの張本人である、PatrickJS こと gdi2290 は、「このパッケージが引き起こした全ての混乱について謝罪する。この問題を改善するために、npm 管理者に連絡した」と述べている。

Checkmarx のソフトウェア・サプライチェーン・セキュリティ責任者である Jossef Harush は、「彼は、ある実験を行い、パッケージを npm に公開した。そして、いまは npm パッケージを削除したいと考えている。しかし、それを、他のパッケージが使っていたら削除できない」と、同社のブログに記している。

このキャンペーンを “依存性地獄” と名付けた Harush は、「この問題は、”everything” が、すべてのパッケージに依存している点にある。つまり、あなたのパッケージが立ち往生しているのは、未知のパッケージが、その削除を妨げているからだ」と指摘している。

この研究者は、”everything” パッケージと、2023年1月に発表された “no-one-left-behind” パッケージの比較を行った。

“left-pad” インシデントを npm の方針転換

Maven Central のようなオープンソース・ソフトウェアのレジストリは不変であり、作者が公開したコンポーネントを削除できないのが通常である。しかし、npm と PyPI は、伝統的に開発者がリリースを削除すること、つまり “yank” することを許可してきた。

しかし、”left-pad” の作者が抗議のために npm パッケージを削除し、インターネットの大部分を破壊した 2016年のインシデントを受けて、npm が取った対策は、作者によるパッケージのアンパブリッシュを困難にすることだった。

そのようなポリシーの変更のひとつとして挙げられるのは、npm レジストリにある他のパッケージが、対象となるパッケージに依存していない場合にのみ、作者はパッケージをアンパブリッシュできるというものである。

皮肉なことに、このポリシーが機能していることで、”everything” の作者である PatrickJS が設定した非常に長い依存関係の連鎖により、問題のパッケージの簡単な削除ができなくなった。

BleepingComputer の観測によると、現時点において “everything” はレジストリ上で生き続けているが、”@everything-registry” スコープの何千ものパッケージは非公開になり、この問題は解決された可能性がある。