← ブログ

プロンプト一つとClaude Fable 5でAPIの脆弱性5件を修正した話

AI/LLM セキュリティ エンジニアリング

VLOP透明性ダッシュボードの裏側では、小さなFastAPIサービスが動いています。TikTok Research APIを模した構造化クエリAPIで、集計済みのEU DSA透明性データを提供するものです。エンドポイントのいくつか——インタラクティブなクエリビルダー、自然言語の「質問」ボックス、概要フィード——は意図的に公開しています。趣味規模のサービスの公開エンドポイントは、誰も見ることを強制されないがゆえに、セキュリティ負債が静かに溜まる場所そのものです。

そこで、Anthropicの新しいClaude 5ファミリーの最初のモデルであるFable 5を搭載したClaude Codeに、見てもらうことにしました。プロンプトは一行:「APIのセキュリティチェックを実行して、脆弱性があれば修正して」。返ってきたのは、それぞれにリグレッションテストが付いた5件の修正と、自身の差分に対するセルフレビューを含むプルリクエストでした。

発見された問題

Webhookコールバックに残っていたSSRFの穴。このAPIでは、クエリにcallback_urlを指定すると、ジョブ完了時にそのURLへPOSTされます——典型的なサーバーサイドリクエストフォージェリ(SSRF)の攻撃面です。既存のガードはプライベート、ループバック、リンクローカル、クラウドメタデータの各レンジをブロックしていましたが、ブロックリスト方式はこの問題に対して形が逆でした。キャリアグレードNAT(100.64.0.0/10)のような「プライベートでも公開でもない」レンジを見逃していたのです。修正ではチェックを反転させ、コールバック先はグローバルにルーティング可能でなければ拒否されるようになりました。

CSV数式インジェクション。クエリ結果はCSVにエクスポートでき、データセットには第三者の透明性報告書由来の自由記述フィールドが含まれます。=+-@で始まるセルは、ExcelやSheetsで開いた瞬間に数式として実行されます——つまり、他社が公表した報告書の中の値が、研究者のマシン上でコードを実行しうるということです。これらの接頭辞を持つテキストセルは、サーバー側とダッシュボードのクライアント側エクスポートの両方で無害化されるようになりました。

無制限のリクエストボディとクエリ複雑度。公開クエリエンドポイントは、認証なしで構造化クエリモデル全体を受け付けます。リクエストボディの大きさにも、クエリが積み上げられる条件の数にも上限がありませんでした。現在は、上限を超えるボディはパース処理に入る前に413で拒否され、クエリモデル自体が条件あたりの値の数、句あたりの条件数、リクエストあたりのフィールド数を制限しています。

APIキー検証のタイミングサイドチャネル。キーは辞書引きで検証されており、最初に異なる文字が現れた時点で比較が打ち切られます——原理的には、応答時間からキーの接頭辞が漏れます。現在は、設定されたすべてのキーに対する定数時間比較になっています。

その他の細かな堅牢化——ページネーションパラメータの上限など、チェックリストを総当たりすれば見つかるが、忙しいメンテナーは見落とすたぐいの小粒な項目です。

驚いたこと

このプルリクエストは、もう一つのAIであるGemini Code Assistの自動レビューをトリガーし、2件の提案が付きました。Fable 5は行動する前に両方を実際のソースコードと照合し——そのうち1件について、ボットの推論が不完全であることを見抜きました。Geminiは、攻撃者が任意の長さで指定できるContent-Lengthヘッダーを整数にパースするとCPUを消費しうると指摘しました。正しいものの軽微な話です。より鋭い問題は、Fable 5が返信で特定し説明したとおり、Python 3.11以降は約4,300桁を超える整数のパースを拒否して例外を送出するため、異常なヘッダーは意図した413ではなく500エラーを生んでいたはずだ、という点でした。さらにGeminiのハードコードされた修正案を、設定された上限に追従する形に一般化し、5,000桁のヘッダーを送るリグレッションテストも追加しました。AIが、別のAIによる最初のAIのコードへのレビューをレビューし、しかもその見解の相違で正しい側に立つ——2026年の予想ビンゴには入っていませんでした。

ここから得たもの

これは以前書いたコンプライアンス業務でのLLM活用と韻を踏んでいます。勝ち筋は、検証可能なアウトプットを持つ構造化されたタスクにあります。小さなコードベースのセキュリティ総点検はまさにそれです——有限のチェックリスト(インジェクション面、SSRF、サイドチャネル、リソース枯渇)を網羅的に適用し、すべての発見はコードを読めば確認でき、すべての修正はテストで固定できます。「網羅的で退屈」な領域こそ、いまやモデルが疲れた人間に安定して勝つ場所です。

判断は私の側に残りました。メトリクスエンドポイントを非認証のままにしてよいか、本番以外でデモキーを許容するか、デモサービスにインメモリのジョブストアで十分か——これらはサービスが何のためのものかに関する脅威モデル上の判断であり、モデルもそれを判断するふりはしませんでした。テストを含む差分の全体はプルリクエストにあります。テストスイートは122件、すべてグリーンです。

esc