JavaScript
Security
npm
ESLint

NPMのeslint-scopeハッキングとNPM全トークン無効化

これを書いているのは日本時間2018年7月13日の3:00ですが、そのうち日本語でいろんなところから情報が出ると思うので、それまでのつなぎとして。「朝出社したらNPMのプライベートパッケージを使うCIがこけてた」とかいった場合に読んでください。

起こったこと

  • 日本時間で7月12日の夜7時頃に公開されたNPMのパッケージ eslint-scope のバージョン 3.7.2 に、何者かによってマルウェアが仕込まれていました。これは「このパッケージをインストールした後に走るpost-installスクリプトが、ユーザのホームディレクトリ ($HOME) 上にある .npmrc を読み取り、そこに書かれている認証トークンを、とある外部サーバに送信する」というものでした。ソースはこれ。認証トークンは手動でも作成できますが、典型的には npm adduser (npm login) したときに裏で生成されて上記の場所に保存されます。
  • 約1時間後に気づかれてこのバージョン自体は削除されましたが、この1時間の間に eslint-scope を(間接的にでも)インストールした人のマシンにあるNPMの認証トークンが、外部サーバに送信された可能性があります。既に数百~数千程度のトークンは攻撃者に流出した可能性が高そうです。
    • eslint 自体がこれに依存しています
    • マルウェアの作者のコードにへっぽこなバグがあったため、Linux系のOSの人については影響を免れているかもしれません。
  • 原理的には、これによって収集したトークンを使えば更に多くのパッケージを同様に感染させてpublishすることができ、芋づる式に大量のパッケージを感染させてさらに大量のトークンを収集するという連鎖が可能です。原理上の話であって実際にそのような自動化攻撃が今確認されているわけではありませんが、放っておけば時間の問題でもあります。
  • このため、「2018-07-12 12:30 UTC (日本時間で12日21:30)より前に作成されたすべてのNPMの全てのトークンが無効化される」という発表があり、約2時間後に本当に無効化されました。

npm intends to invalidate all active tokens, to completely prevent the possibility of stolen tokens being used for malicious purposes. This work is ongoing, but you should expect to need to re-generate tokens for build systems etc. in the next few hours.

https://status.npmjs.org/incidents/dn7c1fgrr7ng

影響範囲とやるべきこと

「全員NPMにログインして自分のトークンを削除して再生成するんだ! 間に合わなくなっても知らんぞー!」……という勢いで書き始めたのが深夜3時でしたが、書いてる途中の深夜4時前にはNPMの既存トークンが強制的に全部無効化されたので、そこまで大慌てすることではなくなりました。盗まれたのはトークンでありパスワードではないので、npm login しなおしてトークンを再生成しましょう。

  • NPMのログインアカウントを持っていない人(NPMの公開パッケージを npm installyarn install でインストールするだけの人)は関係ありません。
  • 万一まだ残っているなら、以下のURLより全トークンを無効化ましょう(これを見ている時点で既に消えているはず)。自分のところでは数年前のトークンとかが何個もありましたが全部消えました。
  • トークンが悪用されていないか確認しましょう。特に、自分がpublish権限のあるパッケージについて、いつの間にか自分の知らない謎の新バージョンがリリースされていないか見ておきましょう。
  • 上記のように原理上は芋づる式に感染を広げられるものである上、そもそも eslint-scope が大本の感染源だという保証すら今のところないので、「昨日のうちにeslint-scope のバージョン 3.7.2 を入れてさえいなければ全く安心」ということではありません。
  • 2段階認証をONにしている場合、トークンだけ盗まれても悪用できなくなりますので、この機会に2段階認証をONにしましょう。似たような事案はまた起きる(か、気づかれていないだけで既に起きている)可能性が高そうです。
  • プライベートパッケージに依存しているCIとかでエラーが出るのは頑張って直しましょう。

以上。間違いがあればコメント欄でご指摘ください。