Claude Code によるアタックサーフェス削減: Anthropic の 3 つのパスを自分のサイトで試し、Anthropic が問わない 4 つ目の問いを加える
Anthropic のスキルはまだ公開されていませんが、手法は半日あれば再構築できます。難しいのは、どこに向けるかの選択です。今回いちばん役に立った発見は壊れていた検証ファイルで、本当に問題だった露出は、3 つのパスが一度も開かなかったデプロイ設定の中にありました。
目次
10月20日、Anthropic の Frontier Red Team は、Claude に別の問いを投げる手法を公開しました。バグがどこにあるかではなく、攻撃者が到達できるのに、到達できる必要がどこにもないコードはどれかを問う手法です。25 のオープンソースプロジェクトに適用して 493 件の問題が見つかり、筆頭に挙げられた事例は OpenSSH でした。デフォルトのインストールで、実験的なポスト量子コードの約 4,500 行が認証前に到達可能になっていたのです。
この手法の発見の部分を、誰の許可もなくテストできる唯一の公開システム、つまりこのサイトで再現しました。3 つのパスをそれぞれ新しいコンテキストで走らせ、指摘はローカルの本番ビルドに対してトレースしています。所要時間は 25 分弱でした。いちばん役に立った発見はアタックサーフェスとは関係のないバグで、今月いちばん深刻だった露出は、3 つのパスのどれも見ない場所にありました。どちらも、この手法は向けた先にあるものを見つけるということ、そして向ける先を決めるのは自分の仕事だということを示しています。
Claude を使った Anthropic のアタックサーフェス削減の手法とは何か
3 つの問いを 3 つのパスで尋ねます。各パスは、前のパスからの短い引き継ぎを除けば空のコンテキストウィンドウから始まります。1 つ目は、デフォルト設定で誰でも到達できるのに、意図された機能のどれも使っていないコードを探します。2 つ目は、認証やプロトコルの状態遷移のような厳格なゲートより前に動くコードを、どの設定についても探します。3 つ目は、セキュリティ制御を黙ってオフにしたり弱めたりするオプションの組み合わせを探します。これを推測のリストで終わらせないのが、確認のステップです。
In every pass, Claude creates an inventory of the entry points from the
code and confirms each finding with a dynamic trace of the program. For
default configuration findings, it designs and implements a gate and
ensures that this causes no change in the program’s default behavior. It
does so by running the project's own test suite (along with a black box
regression suite) against the baseline; it requires modified builds to
have identical results.非デフォルトの設定を変えてしまうゲートは、人間の判断に回されます。これは正しい直感です。デフォルトが一度も使わないものは閉じ、誰かが使うかもしれないものは所有者に任せます。
Anthropic のアタックサーフェスのパスは OpenSSH で何を見つけ、記事は何を書かなかったのか
見出しになる数字は、25 のプロジェクト、500 万行を超えるコードで 493 件の問題です。元になったのは 17,000 を超える設定オプションの一覧で、そのうち 3,842 がセキュリティに関わるものでした。いちばん興味深い分類は 3 つ目のパスから出てきました。
Claude found 162 security sensitive configuration combinations that were
accepted both without an error or warning and without any documentation
of the expected behavior of their interaction. In 94 of those cases, the
combination silently turned off a security control.4 つのプロジェクトで同じパターンが見つかりました。ホスト名で書かれた拒否ルールと、無効にされた逆引き DNS の組み合わせです。サーバーはホスト名のパターンを IP アドレスと比較することになり、ルールは決して一致せず、拒否リストはフェイルオープンになります。別の組み合わせでは、クライアント証明書を必須にしたサーバーが誰でも受け入れていて、そのコードは 21 年間存在していました。
事例研究の中心は OpenSSH です。10.4 の sshd は、クライアントが送ってきた鍵の種類を、その種類が許可されているかを確認する前にパースし、証明書の場合は CA の署名まで検証していました。ML-DSA-44 はデフォルトで有効ではないのに、そのコードは到達可能で、アルゴリズムを明示的に除外していても同じでした。Anthropic は、このコードがデフォルトの sshd における OpenSSH 自身の認証前コードの約 16% にあたると見積もっています。
10.5 のリリースで、確認はパースの前に移されました。その後 Claude はこの確認に 2 つの穴を見つけます。提示されたアルゴリズムとパースされた鍵の種類が食い違いうること、そして証明書の CA 鍵がまだ先に完全な検証を通っていたことです。10.6 で出た修正は確認をパーサーの内側に置き、未認証のクライアントがそれまで到達できたコードのおよそ 5 分の 1 を取り除きました。この修正がしなかったことに注目してください。ML-DSA のコードは削除していません。中に入れてもらっていない相手からは到達できないようにしたのです。
記事が書かなかったことも同じくらい重要です。493 件の誤検知率はなく、OpenSSH 以外でメンテナーが受け入れた指摘の数もなく、コストの数字もありません。著者は、Claude はこれを経済的にこなすと書いてはいます。ゲートを入れたグループについては、どの問題もそれ単体ではすぐに悪用できるものではなかったとはっきり述べています。これは手法の弱点ではなく、手法そのものです。誰かがエクスプロイトを書く前にサーフェスを縮めるのが目的なので、見るべき数字は見つかった脆弱性ではなく、外部の人間がもう到達できなくなったコードの量です。
Anthropic のアタックサーフェス削減スキルは公開されているのか
10月20日の記事と一緒には公開されていません。記事は 3 つのパスを 1 つの再利用できる Claude のスキルにまとめたと説明し、チームが OSS-Scanner に統合中だと書いていますが、リポジトリへのリンクもプロンプトもありません。そのため、以下は説明から手法を再構築したもので、各パスの文言は Anthropic のものではなく私のものです。再構築は難しくありません。この手法の大部分は規律だからです。コンテキストを分けること、ビルドを動かしておくこと、指摘ごとにトレースを取ること、プロジェクト自身のテストをベースラインにすることです。
Claude Code でアタックサーフェス削減を実行するには
本物をローカルでビルドし、すべてのパスをそこに向けます。Next.js サイトなら、テストしたいコミットのワークツリー、本番ビルド、空いているポートでループバックにバインドしたサーバーです (デフォルトでは next start はすべてのインターフェースで待ち受けます)。
git worktree add --detach ../asr HEAD
cd ../asr && npm ci && npm run build
npx next start -H 127.0.0.1 -p 3130次に、どのパスよりも先に、そのサーバーに対してプロジェクト自身のテストを実行し、削ったあとの結果と比べるためのベースラインを作ります。ここでは、リポジトリにもともとある markdown と MCP エンドポイントのテストスクリプトがそれにあたり、どちらも通りました。レイアウトテストはその環境では実行できなかったので、黙って外すのではなく、ここにそう書いておきます。
各パスはそれぞれ専用の Claude Code サブエージェントに渡すので、どのパスも他のパスの結論を引き継ぎません。今回は 3 つを並列で走らせました。3 つのプロンプトには共通のルールがあります。ワークツリーを読むこと、何も変更しないこと、リクエストは localhost にだけ送ること、curl のトレースでその経路に到達することが示された場合だけ指摘として数えること、そして指摘ごとに、何を削るか、どのテストやリクエストでデフォルトの挙動が保たれることを示せるかを挙げることです。パス 1 の問いを、実際に使ったプロンプトから抜粋します。
Which code is reachable in the DEFAULT configuration (no special env
vars, no flags, a normal production build) that does NOT need to be
reachable for the site to do its job? "Does not need to be reachable" =
a route, method, parameter, header path, rewrite, debug branch, or file
that is served but serves no purpose for those jobs.このプロンプトの肝は 2 点です。サイトの役割を、意図的に公開しているエンドポイントも含めて書いているので、パスは意図して用意した機械可読のサーフェスを無駄として指摘しません。そして、ガードを足すよりコードを削除したいと伝えているので、提案される修正の形が変わります。
私の実行は、1 か所で Anthropic のものに届いていません。対象は発見と提案までです。パスの間にはどの削除も適用していないので、Anthropic のループの回帰側、つまり変更したビルドとベースラインの比較は、これらの指摘についてはまだ実行していません。
アタックサーフェス削減のパス 1 は小さな Next.js サイトで何を見つけるのか
パス 1 はテストのベースラインを含めて 5 分半かかり、6 件の指摘と 1 件のデッドコードを確認しました。種類で言えば、どこからもリンクされていないエイリアス、フレームワークがすでに行っている処理、古い構成のために残していたリダイレクト、誰も必要としないレスポンスのメタデータ、もう何の効果もない設定です。提案された修正のほとんどは削除で、1 つは設定 1 行だけです。パスは捨てた誤検知も一覧にしていて、MCP エンドポイントの場合、それは仕様が求めているものの長いリストになります。
実行が終わった時点で 6 件はどれも直っていなかったので、種類だけを書きます。名前を出せる指摘は同じ日の朝に直したもので、セキュリティの問題ではありませんでした。素の URL をデフォルト言語に送るための URL パスのリライトが、サイトのルートに置く必要のある 2 つのファイルまで捕まえていました。Google Search Console の検証ファイルと IndexNow のキーです。どちらも本番で 404 を返していたので、Search Console の再検証も IndexNow のキー検証も、気づかないうちに失敗するところでした。
Anthropic の記事はこの副作用に触れていません。何が到達可能かを証明しなければならないパスは、結果としてサーバーの地図を手にすることになり、地図には余計な道と同じくらいはっきりと、なくなった道も描かれます。
ログインのないサイトでのアタックサーフェス削減のパス 2: 匿名のリクエストはサーバーに何をさせられるのか
このサイトには認証のゲートがどこにもなく、シークレットを確認するものも Webhook を受けるものもありません。そこでパス 2 は、その下にある問いに置き換わりました。匿名のリクエストはサーバーに何をさせられるのか、という問いです。3 分かかり、4 件の指摘が返ってきました。どれも同じ形で、ハンドラーが役割に必要な以上の入力を受け付けているというものです。非公開のものに届いた指摘はありませんでした。そのうち 2 件は、最後まで確認するには副作用を実際に起こすしかなかったので、確認は意図的にローカルビルドで止めています。
制御のないサイトでアタックサーフェス削減のパス 3 がほとんど何も見つけなかったのはなぜか
このサイトでは、保護をオフにするオプションの組み合わせはありませんでした。オフにするものがほとんどなかったからです。組み合わせが保護をオフにできるのは、オフにする保護があるときだけで、認証もクッキーもないサイトでは、パスが食いつく場所がほとんどありません。2 分 15 秒で、確認済みのメタデータの不整合が 1 件、影響を確認できなかった穴が 1 件、潜在的なケースが 1 件見つかりました。
3 つ目のパスは、オフにできる制御を持つものに向けるためのものです。リバースプロキシ、SSH デーモン、VPN のアクセスルールなどです。Anthropic の記事にあるホスト名の拒否ルールやクライアント証明書のケースは、まさにその種類の対象です。
アタックサーフェス削減の 4 つ目の問い: コードが一度も参照しないのに、デプロイは何を公開しているのか
今月見つけたいちばん深刻な露出では、コードにはまったく問題がありませんでした。それは私がデプロイしている静的サイトにあり、原因はそれぞれ単体では妥当な 2 つの設定でした。サイトにはビルドステップがありませんでした。素の HTML には必要ないからです。そのためホスティングプラットフォームはリポジトリのルートをそのままサイトとして配信していました。そして、そのリポジトリで作業しているエージェントは作業メモを同じリポジトリに置いていて、このリポジトリは非公開です。この 2 つが重なって、内部のファイルが推測できる URL で到達可能になり、その状態が何か月も続きました。デプロイ設定を見直したときに、この状態に気づきました。修正は、デプロイするものの許可リストを作り、そのうえで外部から、内部のパスがすべて 404 を返すことを確認することでした。
形としてはパス 3 の指摘です。保護を黙って外すオプションの組み合わせで、違うのはその保護が「このリポジトリは非公開」だったという点だけです。私の 3 つのパスはコードから一覧を作っていて、コードから一覧を作るパスは、コードが名前を挙げているものしか見つけられません。4 つ目の問いはリポジトリから一覧を作り、そのうちどのファイルを配信しているかを動いているビルドに尋ねます。モデルはまったく要りません。ローカルの本番ビルドに対して、追跡されているすべてのファイルをそれ自身の URL パスでリクエストします。
git ls-files -z | grep -zv '^public/' | while IFS= read -r -d '' f; do
code=$(curl -gs -o /dev/null -w '%{http_code}' "http://127.0.0.1:3130/$f")
echo "$code $f"
done > probe.txt
cut -d' ' -f1 probe.txt | sort | uniq -c # status counts
grep -v '^404' probe.txt # everything that did not 404-g が重要です。これがないと curl は Next.js の動的ルート (route) のフォルダー名に含まれる角かっこをグロブとして扱い、そのファイルを黙って飛ばします。このループを最初に実行したときは、34 個がそうなりました。続いて public フォルダーについても、接頭辞を外して同じことをし (Next は public/x.png を /x.png で配信します)、どのソースファイルからも参照されていないファイルをすべて洗い出します。200 は手がかりにすぎません。配信されていると判断する前に、レスポンスの本文をファイルと比べてください。
このサイトでは、修正したループは 7 秒で終わりました。public フォルダー以外の追跡ファイル 679 個のうち、200 を返したものは 1 つもありませんでした。public フォルダーの 345 個のうち、4 個は意図的にブロックしていて、古い記事フォルダーにある画像 6 個はどのソースファイルからも参照されておらず、89 個は参照されていて、246 個はフォントのスライスでした。この 246 個を参照チェックが見落としたのは、それを指定しているスタイルシートが public フォルダーの中にあるからです。grep はヒューリスティックで、証拠になるのは curl です。
再実行では新しいこともわかりました。17 件のリクエストが、404 であるべきところでサーバーエラーを返しました。何も配信されてはいませんでしたが、その日の早い時間に行った到達可能性の変更がこれらのエラーを引き起こしていました。これが、経路を削る前だけでなく、削るたびに再実行すべき理由です。
Next はリポジトリのルートをディレクトリとして配信しません。配信するのはアプリのルート (routes)、ビルドアセット、public フォルダーで、各ルートが何を返すかはコード次第です。問題が起きたサイトには、フレームワークがまったくありませんでした。このチェックにかかるのは数秒で、素の静的デプロイの中には、それを実行するよう促してくれるものは何もありません。
アタックサーフェス削減とバグハンティング: バグを見つけるより経路を閉じるほうがよいのはなぜか
私の考えでは、到達可能なコードを取り除くことは、その中のバグを見つけることより正しい修正です。見つけたバグは 1 つの欠陥に対する 1 つの修正で、そのバグを抱えていたコードは次の欠陥に対しても到達可能なままです。閉じた経路は、そのコードに今後現れるすべての欠陥を道連れにします。誰も報告しないものも含めてです。OpenSSH の事例では、修正を出す価値があると言えるために、誰かが ML-DSA パーサーのメモリバグを見つける必要はありませんでした。
Anthropic の手法は削除よりもゲートを使うことが多く、この 2 つのうち私は、デフォルト以外の設定を誰も使っていない場所では削除に傾きます。ゲートは確認の一種で、確認が縛るのはそれがカバーする経路だけです。10.5 のゲートは提示されたアルゴリズムを見ていた一方で、パーサーは鍵の blob を信用していて、その奥のコードは食い違いひとつで届く距離に残っていました。削除したコードには、2 本目の入り口がありません。代償は、選択の余地がなくなることです。誰かが実験的な経路を取り戻したくなったら、フラグではなくバージョン管理から戻すことになります。そのため、誰かが非デフォルトの構成を動かしている場所では、やはりゲートを使います。これはまさに Anthropic が人間の判断に回しているケースです。
変更をレビューする人との会話も変わります。「ここにバグがある」と言うレポートは、相手にそのバグの検証を求めます。「このコードはデフォルト設定では到達できず、テストスイートの結果も変わらない」と言うパッチは、変更とその証拠を一緒に渡します。
サンドボックスという壁は、別の問いのための別の道具です。srt のようなサンドボックスはプロセスが触れられるものを制限しますが、この手法はそもそも外部の人間が到達できるものを縮めます。そして、これまで見てきたいくつかの脱出では、出口はコードではなく、エージェントに与えられていたサービスや認証情報でした。今回の場合は、丸ごと Web サーバーに渡されたリポジトリです。
アタックサーフェス削減は本番のサービスとローカルビルドのどちらに対して実行すべきか
明日これを実行するなら、パスは本番のサービスではなくローカルの本番ビルドに対して走らせてください。自分の本番環境へのスキャンは、攻撃とまったく同じに見えます。今週、公開中のサイトで漏れている URL を確認したときは、プラットフォームのボット対策がリクエストにチャレンジ画面を挟み、それが解除されるまで死活監視がサイトのダウンを報告していました。また、一部の指摘は、警告している行為を実際にやってみないと確認できず、それは本番ではやりたくないことです。
ローカルビルドは、本番に触れずにアプリケーションの動作を再現します。ホストのキャッシュは再現せず、外向きの通信もそれだけでは隔離しないので、パスがマシンの外に出る何かを起こさないようにしてください。本番は、指摘が実際に生きていることを確かめる 1 回か 2 回のリクエストにだけ使い、それについて書く前に直してください。
01 / ディスカッション
コメント欄はありません。議論は X で行っています。
02 / ほかの記事
Claude アプリで auto mode が標準に: チェックが止めるもの、89% の調査が測ったもの
Anthropic の調査は、その設計については正直です。疲れたテスターに、仕込んだ危険なコマンドを 1 つ見せただけです。誤検知率も実運用での見逃し率も示しておらず、クラウドセッションには戻る先の Manual モードがありません。
Claude Code の料金 2026:同じ作業に Pro、Max、API はいくら請求するか
プランの料金は定額で、トークン単価も公開されています。そのため比較はただの計算に見えますが、そう単純ではありません。Claude Code は支払い方によって会話のキャッシュの仕方を変えます。そしてサブスクリプションの利用量をドル換算するのに多くの人が使うツールは、実際に使っていたキャッシュで計算するため、乗り換えた後に使うことになるキャッシュの料金は出てきません。
Claude Code のフック:誘導には強く、関門としては弱い
フックはモデルが同意するかどうかに関係なく実行されます。そのためフォーマットのような雑用や、エージェントを望むルートへ誘導する用途には向いています。関門としては見た目より弱く、指定したツールしか検査せず、チェック自体が壊れるとブロックを明示的に有効にしない限り呼び出しは通り、構成によっては、フックがブロックした呼び出しを mod が承認できてしまいます。