PHPパッケージ管理のデファクトスタンダードである Composer に、GitHub OAuth トークンをログへ平文出力してしまう脆弱性が公開された。CI/CDの実行ログやエラーログにトークンが残存している可能性があり、悪用されればプライベートリポジトリのソースコードが外部から閲覧される恐れがある。今日中のトークンローテーションが事実上の必須対応となる。
何が起きたか
2026年5月14日、Composer プロジェクトが GitHub Security Advisory として GHSA-f9f8-rm49-7jv2: Composer leaks contents of tokens configured as GitHub OAuth tokens を公開した。設定済みの GitHub OAuth トークンの内容が、Composer の処理過程でログ出力にリークしてしまうという内容だ。
Composer は PHP におけるパッケージ管理ツールであり、Python における pip、Node.js における npm に相当する。Laravel や Symfony を使うほぼすべての PHP プロジェクトが依存しており、Packagist 経由のインストールに加え、プライベートリポジトリへのアクセスのために GitHub OAuth トークンを auth.json や COMPOSER_AUTH 環境変数に設定しているケースが非常に多い。
問題は、このトークンが Composer の出力するログ・デバッグ出力・エラーメッセージのいずれかに含まれてしまっていた、という点にある。composer install --verbose や CI 上で -vvv を有効化していたケース、あるいはエラー発生時のスタックトレースなどが想定される経路だ。HackerNews でも 55pt / 20コメント前後で急上昇しており、PHP エコシステム全体での影響が懸念されている。
なぜこのニュースが重要か
GitHub OAuth トークン(gho_ プレフィックスや ghp_ 形式の PAT を含む)は、設定されたスコープに応じてプライベートリポジトリの読み取り、場合によっては書き込み権限まで持つ。漏洩経路として現実的に怖いのは以下のパターンだ。
- CI/CD のビルドログ: GitHub Actions、GitLab CI、CircleCI のジョブログにトークンが平文で残り、リポジトリの Read 権限を持つメンバー全員が閲覧可能になる
- エラー監視 SaaS: Sentry、Datadog、Rollbar などにスタックトレースとして送信され、SaaS 側に蓄積される
- コンテナイメージ:
composer installをビルドステップに含むイメージのレイヤーキャッシュに残存
特に CI ログは「インシデント後にトークンを無効化しても、すでに第三者がログをダウンロード済み」というケースを排除できない。よって**トークンのローテーションは「やった方がよい」ではなく「やらないと安全側に倒せない」**性質の対応になる。
エンジニア視点での技術深掘り
実装面で確認すべきポイントを整理する。
1. 影響範囲の特定
composer.json や composer.lock の存在に加え、以下を grep する。
# プロジェクト内のトークン設定箇所
grep -r "github-oauth" . --include="*.json"
grep -rE "(gho_|ghp_|github_pat_)" .
# CI 設定で Composer を呼んでいる箇所
grep -rE "composer (install|update|require)" .github/ .gitlab-ci.yml
2. CI ログの棚卸し
GitHub Actions の場合、過去のワークフローログは API 経由で一括取得できる。
gh run list --limit 100 --json databaseId \
| jq -r '.[].databaseId' \
| xargs -I{} gh run view {} --log | grep -E "gho_|ghp_|github_pat_"
ヒットがあれば、そのログは削除(gh api -X DELETE /repos/OWNER/REPO/actions/runs/{run_id}/logs)しつつ、トークンを即座に revoke する。
3. ローテーション手順
Personal Access Token であれば GitHub Settings → Developer settings → Personal access tokens から失効。GitHub App や OAuth App で発行している場合は、POST /applications/{client_id}/token の DELETE で失効可能だ。
新トークンは auth.json の直接記述ではなく、CI のシークレット変数 + COMPOSER_AUTH 環境変数経由での注入に切り替えるのが望ましい。
export COMPOSER_AUTH='{"github-oauth":{"github.com":"'"$GH_TOKEN"'"}}'
composer install --no-interaction
4. 恒久対策
Composer 本体の修正版が advisory に記載されているはずなので、composer self-update で最新版に上げる。加えて、長期的には Fine-grained Personal Access Token への移行、もしくは GitHub App による短命トークン(1時間程度の installation token)の発行に切り替え、漏洩時の被害を時間軸で限定する設計が望ましい。
経営者・開発責任者として次に取るべき動き
技術部門に対して、本日中に以下を依頼するのが現実的な落とし所だ。
- 棚卸し: Composer を使っている PHP プロジェクトと、GitHub トークンを設定している箇所のリストアップ
- ローテーション: 該当トークンの即時失効と再発行。新トークンは CI シークレット経由で配布
- ログ監査: 過去 CI ログ・エラー監視 SaaS にトークン文字列が残っていないかの grep と、ヒット時のログ削除
- Composer 本体のアップデート: 修正バージョンへの更新を全リポジトリで実施
- 被害確認: GitHub の Audit Log(Enterprise / Organization)で、当該トークンによる想定外の clone・API 呼び出しがないかを確認
特に 5 は見落とされやすい。漏洩したトークンですでにリポジトリが clone されていた場合、ローテーション後もソースコード自体は外部に出ているため、ハードコードされた API キーや DB 認証情報の有無を別途確認し、それらも併せてローテーションする必要がある。
シークレット管理は「漏れない前提」から「漏れる前提」に設計思想がシフトして久しいが、今回のように管理ツール自体がリーク元になるケースは、その思想の正しさを改めて突きつけてくる。短命トークン化と最小権限化、そしてシークレットスキャンの自動化を、これを機に組織標準として整備しておきたい。
動画でも詳しく
動画は記事冒頭の埋め込みからフル尺で視聴できます。
