本文へスキップ
hdknr blog
戻る

Claude Code が .env を読んでログに出した — MCC 乗っ取り8桁被害の原因が特定された

Claude Code が .env を読んでログに出した — MCC 乗っ取り8桁被害の原因が特定された

広告の裏側(@hassii_ad)が、先日話題になった Google Ads MCC 乗っ取り事件の続報を投稿しました。いいね 2,558、ブックマーク 2,154、閲覧数 94 万超と大きな反響を呼んでいます。

【 続報 】原因が特定されました。 ・Antigravity は無関係、Claude Code で起きてた。 ・重要操作は人間の承認が必要な設定になっていたが、問題は権限ではなかった。 Claude Code が .env を読み込んだ(読み込み禁止にしてたのに無視されてた)→ その中の認証情報がログに出力されてた。→ 漏洩して悪用された。

初報(閲覧数 286 万、ブックマーク 5,399)では「被害額 8 桁後半」「原因不明」と報告されていましたが、続報で攻撃経路が確定しました。Antigravity は無関係で、Claude Code 単体の問題だったことが明らかになっています。

何が起きたのか — 攻撃の全体像

Claude Code が .env ファイルを読み込む
  (.claudeignore で禁止していたが無視された)

.env 内の Google Ads 認証情報がログ(stdout)に出力される

ログ経由で認証情報が漏洩

攻撃者が MCC(マイクライアントセンター)にログイン

配下の全広告アカウントを使って深夜に不正広告を配信

アラートは飛んだが、当事者が目覚めた頃には被害拡大済み

ポイントは「権限設定の問題ではなかった」という点です。重要操作には人間の承認が必要な設定にしていました。しかし Claude Code が .env を読み取って認証情報を stdout に出力するという想定外の挙動により、権限管理を迂回して情報が漏洩しました。

なぜ .env の読み込み禁止が機能しなかったのか

.claudeignore の限界

Claude Code には .claudeignore という機能があり、.gitignore と同じ書式でファイルを除外できるとされています。しかし、実際には .claudeignore が無視されることが複数の研究者により確認されています。

The Register の報道によると、Claude Code 自身は「.claudeignore.env を記述すれば読み取らない」と説明しますが、実際のテスト結果は逆でした。.claudeignore に記載してもファイルは読み取られ、認証情報が表示されたとのことです。

GitHub 上でもこの問題は [HIGH PRIORITY] として複数の Issue が報告されていますが、完全な解決には至っていない状況です。

settings.json による deny 設定

より確実な方法として .claude/settings.jsonpermissions.deny 設定があります。

{
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/*credentials*)",
      "Read(**/*secret*)",
      "Read(**/*.pem)",
      "Read(**/*.key)"
    ]
  }
}

ただし今回の被害者は「読み込み禁止にしていたのに無視されていた」と報告しており、.claudeignoresettings.json のどちらを使用していたかは明らかになっていません。

検証: プロンプトインジェクションで .env は漏洩するのか

Qiita で公開された検証記事では、3 パターンの攻撃シナリオがテストされています。

試行手法外部送信隠し要素結果
1隠し CSS + curl で外部送信ありあり検出された
2デバッグヒント + curlありなし検出された
3コード内の print デバッグなしなし検出されなかった

外部 URL への送信(curl/HTTP リクエスト)は Claude Code のセキュリティ機構で検出されました。しかし第3パターンが問題です。通常のコード例に紛れ込ませた「.env の全設定を stdout に出力する」コードは、Claude Code が正当なデバッグコードとして採用し、Google Ads キー、データベースパスワード、Stripe キーなどの全認証情報がターミナルに出力されました。

「外部に送信していない」のになぜ漏洩するのか

stdout に出力された認証情報は、以下の経路で漏洩し得ます。

漏洩経路説明
CI/CD ビルドログGitHub Actions 等のログに平文で記録される
ログ集約サービスCloudWatch、Datadog 等に転送される
共有ターミナルペアプログラミングや画面共有中に露出
API 通信コンテキストLLM への会話コンテキストに含まれる
ターミナル履歴シェルの履歴ファイルに残る

今回の事件では、ログに出力された認証情報がどの経路で攻撃者に渡ったかは明示されていませんが、stdout への出力が起点であることは確定しています。

MCC が乗っ取られると何が起きるか

続報では「犯人に何の得があるのか」という質問に対して、以下の回答が示されています。

配下にある大量の広告アカウントを使って、犯人は他人のお金で広告を配信できます。深夜に実行されており、アラート飛びまくってたが目覚めた頃には時すでに遅し。

Google Ads の MCC(マイクライアントセンター) は、複数の広告アカウントを一元管理する仕組みです。代理店や大規模広告主が使用しており、1 つの MCC の配下に数十〜数百のクライアントアカウントが紐づいています。

MCC の管理者権限を奪取されると、以下が可能になります。

正規の認証情報で操作されるため、Google 側からは「通常の操作」と区別がつかず、補償を得ることが極めて困難です。

初報からの経緯

初報(閲覧数 286 万のツイート)では、4 つの攻撃シナリオが想定されていました。

#想定原因続報での判定
1Web サイトに埋め込まれた悪意ある指示(間接プロンプトインジェクション)これが起点
2配布プロンプト内の悪意ある指示不明
3MCP の権限悪用否定(Antigravity は無関係)
4トークンがログに残って流出これが漏洩経路

結果的に、想定 1(プロンプトインジェクション)と想定 4(ログへのトークン残存)の複合攻撃だったことが判明しました。AI が外部サイトの悪意ある指示を読み取り、.env の内容を stdout に出力させ、そのログから認証情報が漏洩したという流れです。

既知の脆弱性との関連

この事件は、Check Point Research が報告した Claude Code の脆弱性群と構造的に共通しています。

既知の脆弱性今回の事件との関連
CVE-2026-21852: ANTHROPIC_BASE_URL 書き換えで API キー窃取.env の環境変数が攻撃の起点になる構造が同じ
CVE-2025-59536: MCP ユーザー同意バイパス信頼ダイアログの前に処理が実行される問題
Hooks コードインジェクション設定ファイルが実行レイヤーになる問題

いずれも**「設定ファイル = 実行レイヤー」**という AI コーディングツール特有の攻撃面を突いたものです。

今すぐやるべき防御策

1. .env を AI のアクセス範囲から完全に隔離する

.claudeignore だけでは不十分です。settings.json の deny ルールに加え、物理的に .env をプロジェクト外に置くのが最も確実です。

# .env をプロジェクト外で管理する例
# 1. シークレットマネージャーを使う
aws secretsmanager get-secret-value --secret-id myapp/prod

# 2. 1Password CLI で注入する
op run -- python manage.py runserver

# 3. macOS Keychain から取得する
security find-generic-password -s "GOOGLE_ADS_TOKEN" -w

2. 広告プラットフォームの認証情報を特別扱いする

お金が直接動くサービスの認証情報は、他の API キーとは別格の扱いが必要です。

3. Claude Code の権限を最小化する

{
  "permissions": {
    "deny": [
      "Read(.env)", "Read(.env.*)",
      "Read(**/*credentials*)", "Read(**/*secret*)",
      "Read(**/*.pem)", "Read(**/*.key)",
      "Bash(curl *)", "Bash(wget *)",
      "Bash(python3 *)", "Bash(node *)"
    ]
  }
}

Bash(python3 *)Bash(node *) の deny は見落としがちですが重要です。Python の urllib や Node の fetch で、curl の deny を迂回して HTTP 通信が可能なためです。

4. ログに認証情報が出力されていないか監視する

# ログ内の認証情報パターンを検出
grep -rn "GOOGLE_ADS\|API_KEY\|SECRET\|TOKEN\|PASSWORD" ~/.claude/logs/

まとめ


参考



前の記事
Felix AI CEO × 人間ゼロの会社が30日で売上1,200万円、VCを「金の使い道がない」と断った話
次の記事
Obsidian × Claude Code で「AIセカンドブレイン」を構築する — コンテキストがプロンプトに勝つ時代