LinkedIn 求人オファーに仕込まれたバックドア — npm prepare スクリプト一行が開発者マシンを潜在 RAT に変える場所
LinkedIn 求人オファーに仕込まれたバックドア — npm prepare スクリプト一行が開発者マシンを潜在 RAT に変える場所
求人メッセージ一通が GitHub リポジトリ一つを経由して、開発者のマシンを RAT に変えるソーシャルエンジニアリングの新しい標本。Lazarus か、一般 cybercrime か、それとも両者の間の灰色地帯か。
導入 — 求人オファーと共に届いた一行
2026 年 6 月 16 日、ロシア出身のフルスタック Python 開発者 Roman Imankulov が自身のブログに一本の事後分析を上げた。タイトルは 「LinkedIn 求人オファーに仕込まれたバックドア (A backdoor in a LinkedIn job offer)」 だった。Hacker News のトップに上がり 1541 点を集め、コメント 294 件が付いた。同じ週のどのセキュリティニュース — Anthropic の Fable 5 停止、Fedora の AI エージェント侵入 — も同じ位置には届かなかった。一人の開発者の一人称報告がこれほど大きな反応を集めた理由は、その報告がすべての開発者が毎日受け取る一種類のメッセージ — 「あなたに合う席があります」 という LinkedIn メッセージ — の最も暗い側の角を可視化したからである。
事件の核は一行に整理できる。リクルーターが LinkedIn でアプローチし、数日間自然な会話を交わした末、「弊社の broken POC があるので、lead engineer になる方ならコードレビューをお願いしたい」 と GitHub リポジトリのリンクを送ってきた。そのリポジトリの app/test/index.js に RCE (リモートコード実行) バックドアが潜んでおり、npm install の prepare ライフサイクルフックを通じて自動実行されるよう設計されていた。すなわち候補者がリポジトリを clone して npm install を一度叩いただけで、そのマシンに任意命令を受け取れるバックドアが入る、という絵だ。Imankulov はまさにその一行の発見の事後を書いたのだ。
事件のメカニズム — どこで、誰が、どう
攻撃は四段階で進んだ。第一に、LinkedIn メッセージの自然さ。 リクルーターのプロフィールは、実在する芸術分野の記者のアイデンティティを盗用したものだった。写真、経歴、学歴のすべてが実在人物の情報だった。Imankulov もこの段階では疑わなかった。メッセージのトーンも一行の spam ではなく、数日間にわたる自然な会話 — 会社紹介、ポジション説明、日程調整 — だった。ソーシャルエンジニアリングの第一段階は正にそれである。「この人物は本物だ」 という信頼を時間をかけて築く仕事。
第二に、GitHub リポジトリの偽装。 リクルーターが送ったリポジトリは、ある実在のフルスタック開発者のアイデンティティで 39 件のコミットが積み上げられた様相だった。そのフルスタック開発者も実在の人物で、その人の GitHub アカウント自体が盗用されたのではなく、別の fake アカウントがその人の名前を借りていた。39 件のコミットが自然に積み上げられているという事実そのものが 「このリポジトリは実在するプロジェクトの作業記録だ」 というシグナルを作る。使い捨ての trap repo ではないように見せる偽装である。
第三に、npm prepare ライフサイクルの悪用。 バックドアの位置は app/test/index.js — テストスイートに見せかけたディレクトリ内のファイルだった。だがそのファイルが直接実行される必要はなかった。package.json の scripts.prepare がそのファイルを呼ぶ一行を持っていたためだ。npm install が終わった瞬間 (またはパッケージが publish される直前、または git dependency がインストールされる瞬間)、prepare フックが自動実行される。ユーザーの明示的な命令なしで。開発者のマシンで最も日常的な命令 — npm install — がバックドアのトリガーになる場所だ。
第四に、ペイロードの正体。 バックドアコードは一次的には外部 C&C サーバへ接続して任意の命令を受け取り実行する RAT (Remote Access Trojan) の第一段階だった。直接的なペイロード — パスワード窃盗、暗号通貨ウォレット窃盗、ランサムウェアの設置 — はバックドア自体に含まれていなかった。その代わり、二次ペイロードを C&C サーバから動的に受け取って実行する。これは偵察段階と本格攻撃段階を分離する標準的な APT (advanced persistent threat) パターンである。
Imankulov の事後報告は GitHub と LinkedIn の双方に通報を済ませたという一行で結ばれる。だがその一行に重い追加が付く。「通報したが何も変わらなかった。そのコードは今もそこにある」 。報告の公開時点でも同じリポジトリが同じ場所で、同じバックドアを仕込んだまま生きているという事実だ。GitHub の abuse report 処理速度、LinkedIn の偽プロフィール摘発速度の双方が、同じ場所で失敗した。
ソーシャルエンジニアリングの新しい標本 — 誰が、なぜこういう攻撃をするのか
この攻撃の attribution は Imankulov の記事で直接試みられない。だが同じパターン — LinkedIn の偽リクルーター + GitHub リポジトリ + npm prepare バックドア — は 2024 年からセキュリティコミュニティが追跡してきた馴染みのある絵柄だ。最も有力な attribution の候補は二つのグループである。
第一に、Lazarus Group (北朝鮮)。 2024 年 8 月 Mandiant の報告書がまさに同じパターンを整理した。偽のリクルーターが LinkedIn でフルスタックまたはブロックチェーン開発者にアプローチし、GitHub のトラップリポジトリへ誘導する。ペイロードは cryptocurrency wallet 窃盗が主な目標だった。2025 年 SecurityWeek の後続報道も、同じグループが同じパターンを変形して運用している状況を整理した。Imankulov が受け取ったメッセージが cryptocurrency startup の lead engineer の席を提示したという事実は、この attribution の最も強い状況証拠だ。
第二に、一般 cybercrime gang。 同じパターンを一般 cybercrime gang が模倣する事例が 2025 年後半から報告され始めた。attribution の非対称は明らかだ。同じ道具、同じパターン、異なる動機 — 一方は国家資金調達、他方は直接窃盗。二つの動機はペイロードの正体で分かれる。Lazarus のペイロードは cryptocurrency wallet の mnemonic と private key を狙う。一般 cybercrime のペイロードはランサムウェアまたは一般 credential 窃盗を狙う。Imankulov はバックドアの二次ペイロードを trigger していないため、正確な正体は分からない。
attribution の結果とは無関係に、この攻撃が生むシステミックな脅威は明らかだ。毎日 LinkedIn で求人メッセージを受け取るすべての開発者が同じ表面の上にいる。その表面は広く、浅い。一行の自然なメッセージ、一つの GitHub リポジトリ、一度の npm install — この三段階はすべて日常の一部だ。日常の一部にトラップが紛れ込むという事実が、この攻撃をソーシャルエンジニアリングの新しい標本にする。
この風景で最も深い非対称は何か。攻撃者のコストは小さい。偽の LinkedIn プロフィールを一つ作るのに数日、GitHub リポジトリを一つ偽装するのに数日、自然な会話のために LLM の助けを借りるのに追加時間がかかる。同じ LinkedIn プロフィールが同時に数十人の候補者にアプローチできる。候補者のコストは大きい。一度の npm install で自分のマシンが潜在 RAT に変わりうる。結果として非対称は二桁以上である。
ここに LLM 時代の新しい変数が重なる。Imankulov の記事では直接言及されないが、自然な LinkedIn メッセージの作成を LLM が支援した可能性が非常に高い。一行の片言の spam が 5 年前の標本なら、数日にわたる自然な多言語会話が 2026 年の標本だ。ユーザー jhhh のコメントが正確に突く。「LLM でソーシャルエンジニアリングの会話コストが 0 に収束する」 。同じ非対称が求人なりすましの新しい武器になっている。
実務者への含意 — パラノイアのコストと実効
Imankulov の提言は小さい。だが正確だ。
第一に、npm install の自動 prepare フックを止めよ。 npm install --ignore-scripts が最も単純な答えだ。この一つのフラグが prepare、install、postinstall などすべてのライフサイクルフックの自動実行を止める。正規のパッケージの一部はこのフックに依存するため、一部パッケージのビルドが失敗しうる。そのビルドをユーザーが明示的に確認して再実行する追加段階がパラノイアのコストだ。Imankulov のケースでこのフラグがあれば、バックドアは自動実行されなかった。
第二に、コードレビューは read-only の道具で。 GitHub のウェブ UI または別途の read-only 環境でコードを見る。Clone → install → run の三段階が日常的なコードレビューの一部であるなら、その三段階がトラップのトリガーになる。新しいコードを初めて見る段階では、その三段階を踏まずに GitHub の raw ファイルビューや grep.app のような道具で一次検討するべきだ。
第三に、偽リクルーターのシグナルを学習せよ。 数日の自然な会話はもはや真摯さのシグナルではない。LLM 時代には数日の自然な会話の生成コストが小さい。疑うべきシグナルは別の場所にある。(a) 会社ドメインのメールではなく LinkedIn メッセージにだけ依存しているか。(b) ビデオ会議を回避しているか。(c) コードレビューを頼む際、自社の社内 GitHub ではなく外部リポジトリを指しているか。三つともトラップの正確なシグナルだ。
第四に、会社側の対応方針。 GitHub、LinkedIn、npm registry の abuse report 処理速度が改善されない限り、この攻撃は続く。方針の答えは二系統だ。(a) GitHub の新規リポジトリ作成時に prepare フックの挙動への明示的な警告表示。(b) LinkedIn のリクルータープロフィールの自社ドメインメール認証の義務化。両方ともユーザー体験の摩擦を増やすが、Imankulov の事後報告の最後の一行 — 「そのコードは今もそこにある」 — が指す方針の空白を埋める。
結論 — 一行の prepare が可視化した風景
Imankulov の事後報告が 1541 点を集めた理由は、その風景の一部 — npm prepare フック一行 — が最も日常的な命令の一部だからだ。すべての開発者が毎日 npm install を打つ。その一つの命令が潜在 RAT のトリガーになりうるという事実が、堅いシグナルとなって 1541 点の反応を生んだ。
本当の問いはその次だ。同じ風景は npm だけの風景なのか、それとも他のエコシステム — pip の setup.py、cargo の build.rs、gem のネイティブ拡張 — の風景なのか。答えは明らかだ。すべてのエコシステムが同じ表面の上にある。npm の prepare フックは最も頻繁に悪用される場所だが、同じ種類の自動実行フックがすべてのエコシステムの標準の一部だ。Imankulov の一事例が試作であり、その試作が他のエコシステムに移るのは時間の問題だ。その日まで我々ができることは、--ignore-scripts 一つのフラグ程度の小さなパラノイアを日常の一部として受け入れることだ。
出典: