なぜ危ないのか
AIはユーザーが明示しなくても動作デモのために外部エンドポイントへのfetch呼び出しを自動で挿入することがある。特にフォーム送信やボタンクリックのサンプルを生成する際、SlackやDiscordのWebhook URLをハードコードして「動くデモ」を作ろうとする傾向がある。この挙動は意図的ではないが、ユーザーがソースを確認しないまま共有するとURLが外部に流出する。
Webhook URLはAPIキーと異なり、URLを知っているだけで認証不要でリクエストを送れる設計が多い。つまり、HTMLのソースを閲覧できた時点でそのURLへの投稿権限が与えられてしまう。社内Slackチャンネルへ外部から任意のメッセージを投稿されると、フィッシング誘導や偽の業務連絡として悪用されるリスクが高い。
- 相手がログインなしで開ける状態か確認する
- PCとスマホで最低1回ずつ表示を確認する
- 内部情報・個人情報・不要な外部送信が残っていないか見る
- レビュー期限と修正時の差し替え方を決めておく
ソースで見る場所
スキャンの基本はgrepコマンドによる文字列検索だ。`grep -rE 'hooks\.(slack|discord)|webhook\.site' ./output/` のように対象ディレクトリを指定して実行すると、サブディレクトリを含めてWebhook URLが検出される。CI/CDパイプラインに組み込む場合は終了コードを確認し、マッチがあればビルドを失敗させる設定にする。
JavaScriptがminify(圧縮)されている場合は文字列がそのまま残るため通常のgrepで検出できる。一方、難読化ツールでUnicode/16進数エスケープされているとパターンマッチが難しくなる。その場合はブラウザのNetworkタブでリクエスト先URLを確認する動的チェックを補完的に行うか、`truffleHog`や`detect-secrets`といったシークレットスキャナーを導入して静的解析を強化する。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
安全に共有する設定
AIへのプロンプトに「外部エンドポイントのURLを直接コードに書かず、`__WEBHOOK_URL__`のようなプレースホルダを使うこと」という制約を加える。この一文を入れるだけでAIは実URLを生成しなくなり、生成後に検索するとプレースホルダのみが見つかる状態になる。プレースホルダが残ったまま共有しても第三者は送信先を特定できないため、漏えいリスクが実質ゼロになる。
スキャン自動化には`pre-commit`フックが便利だ。`.pre-commit-config.yaml`に`gitleaks`を追加しておくと、コミット前にシークレット検出が走り、マッチがある場合はコミットをブロックする。HTMLファイルをGit管理している場合はこれだけで大半のケースを防げる。Gitを使わない場合はNode.jsスクリプトでgrepを実行してHTMLを共有フォルダに転送するシェルスクリプトを作り、スキャン通過後のみ転送する仕組みを組む。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
再発防止ルール
チームで使うAIプロンプトテンプレートにセキュリティ制約を標準として埋め込む。「外部APIコールは環境変数または設定ファイル参照で記述し、URLをHTMLに直書きしない」という一節を全てのHTMLプロンプト共通のシステムプロンプトとして管理することで、個人の判断に依存しない運用ができる。
インシデントが発生した場合に備えてエスカレーションフローも整備しておく。Webhook URLが漏えいしたと判明した時点で、①当該WebhookをSlack/Discord管理画面で削除、②共有リンクを無効化、③受け取ったレビュアーへ使用しないよう通知、④原因となったHTMLファイルを削除またはURLを無効化の4ステップを初動として実施できるよう手順書にまとめておく。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
よくある質問
プロンプトでプレースホルダを指示してもAIが無視することはありますか?
指示を無視することはまれだが、長いプロンプトの後半に制約を書くと見落とされやすい。制約はプロンプトの冒頭に置き、「Webhook URLを含む外部エンドポイントは必ずプレースホルダにすること」と太字や区切り線で強調するとより確実に反映される。
gitleaksはどのくらいの精度でWebhook URLを検出できますか?
Slack・Discord・GitHubのWebhookは既定のルールセットに含まれており、URL形式が正確であれば高い確率で検出できる。独自ドメインのWebhookは追加ルールをgitleaks.tomlに記述する必要がある。
GitHubを使わずローカルだけでHTMLを管理している場合のスキャン方法は?
Node.jsスクリプトかシェルスクリプトでgrepを実行し、マッチがある場合はスクリプトが終了コード1を返すよう記述する。HTMLを共有フォルダへ移動するコマンドの前にこのスクリプトを実行する習慣をつけると、CI環境がなくても手元で同等のガードが機能する。