イントロ: まず自分に向ける
誰かに分解される前に、自分のアプリにREAを向けよう。私たちは使い捨てのクラウドサンドボックスから、稼働中の自社サイトにREAを向け、見つかった問題を直し、プルリクエストまで出した。
REAは、大量の動画が他人のソフトに向けてきたリバースエンジニアリングのスキルだ。私たちのサイトでは、13分足らず、書き込みリクエストを1つも送らずに、どのウェブサイトでもうちのメーリングリストを埋められることを示した。コメントbotの1日の上限が、サイトからダウンロードされるJavaScriptの中に入っていることも見つけた。修正後は、以前すり抜けていたリクエストが拒否される。
結果として、同じ監査を自分のアプリで行うための6つのルールが得られた。使い捨てサンドボックス、正確なターゲット、findingsの仕分け、バンドルに入った設定、エンドポイントのブレーキ、そして修正の証明だ。
REAとは何か、どう入れるか
REAはReverse Engineer Anythingの略で、Claude Codeに自分が出荷したアプリを分解させるためのツール一式だ。リバースエンジニアリングとは、完成品からその作りを突き止めることで、工場の設計図なしに車を読み解く整備士のようなものだ。
REAはソースコードを読むのではなく、バンドルを読む。バンドルとは、サイトが実際にすべての訪問者へ送るJavaScriptのことだ。そのバンドルから、ルート、ページが呼ぶエンドポイント、うっかり残したものを洗い出す。ソースを返してくれるわけではなく、手に入るのは証拠だけだ。REA自身のドキュメントも、これはサンドボックスではないと書いている。
入れ方は次のとおり。
- 公式パッケージからREAを入れ、バージョンを固定する。1週間で6回リリースされたからだ。
- Claude Code向けのセットアップを実行する。
- compactプロファイルを有効にする。100を優に超えるツールがセッションに読み込まれるためだ。
- 公式リポジトリからだけ入れる。マルウェア入りの偽物がすでに出回っている。
サンドボックスでインストールしたとき、エージェントは何かに触れる前に、まずパッケージが公式リポジトリを指していることを確認した。セットアップはスキルを入れたがツールサーバーは入れなかったので、Claude Codeは同じツールのコマンドライン版をそのまま使った。セットアップ後にツールが表示されなくても、再起動は要らない。同じ手順をターミナルから呼べばいい。
ルール1: 被害が出ない場所で動かす
最初のルールは、どこで動かすかだ。エージェントにブラウザを操作させ、ダウンロードしたツールを本番アプリに向けて走らせることになる。自分のノートPCでは、そのエージェントが鍵、ほかのプロジェクト、ログイン中のあらゆるアカウントのすぐ隣にいる。REA自身のセキュリティノートにもはっきり書かれている。これはサンドボックスではない。
サンドボックスは使い捨てのマシンだ。何が壊れても中だけで済み、あとで消せばいい。リポジトリに対して使い捨てサンドボックスを開き、監査はすべてそこで行う。自分のマシンでは絶対にやらない。
私たちはKosukeを使った。自分のサブスクリプションでClaude Codeを、使い捨てのクラウドマシン内で動かせるサービスだ。リポジトリを選び、アプリの起動方法をデプロイエージェントに伝えると、プレビューが出る。動いているアプリが表示されるリンクだ。チャットごとに専用のブランチ、つまり自分用のコードのコピーが作られ、最後はプルリクエストで終わる。サイトをインポートすると、エージェントはパッケージマネージャーとヘッドレスブラウザを入れ、メモリを測って、マシンのサイズも自分で選んだ。数分後には、本物のサイトがチャットの隣で動いていた。ほかの誰も触らないブランチの上で。
以前のテストでのわなが1つある。まっさらなNext.jsアプリがプレビューに表示されたのに、ページが何も反応しなかった。直すにはNextの設定に、プレビューのアドレスを許可する1行を足す。それでページが動き出す。
限界は、これが箱に入れただけの同じClaude Codeだということだ。ローカルの仮想マシンやコンテナでも同じ役目を果たす。大事なのは箱であって、ブランドではない。
開示: Kosukeは上位プランを無料で使わせてくれた。登録直後に「Promo code」欄へコード AIDIVE2026 を入力すると、通常の10ドルではなく30ドル分のクレジットがもらえる。
ルール2: URLを正確に1つ、書き込みは全部ブロック
2つ目のルールは、REAに実際に何を伝えるかだ。「アプリを監査して」とだけ言うと、REAのスキルは止まって、どのアプリかを聞いてくる。
REAは自分でブラウザを開くこともない。そこで、デバッグポートを付けてブラウザを自分で起動する。デバッグポートとは、ツールがページの動きをすべて見られるようにする入口だ。次の順番で設定する。
- デバッグポートはループバックに置く。自分のマシンからしか届かないアドレスだ。ブラウザには新しいプロファイルを使う。
- ページを読み込む前に、書き込みリクエストをすべてブロックする。これで監査はサイトを読めるが、フォームの送信も変更もできない。
- そこで初めて、読ませたいページをREAに正確に指定する。
私たちのプロンプトでは、無料クラブの2ページを名指しし、平易な言葉でルールを1つ書いた。本番サイトには絶対に書き込みを送らない、と。これは重要だった。そのページのフォームは、実在の人たちが載っている本物のメーリングリストにつながっているからだ。エージェントはこのルールを真剣に受け止め、読み取りは通してそれ以外をすべて止める小さなガードを自分で書いた。監査の間、そのガードは分析スクリプトからの6回の試みを止め、登録フォームには1つもリクエストが届かなかった。
そのうえでREAが仕事をした。各ページを調べ、各バンドルを読み、スクリーンショットを撮り、スクリプトをリポジトリの外に書き出した。
限界は、REAがアタッチしている間に読み込まれたものしか見えないことだ。それより前に起きたことは、レポート上unknownのままになる。それでも、自分の稼働中アプリのレポートが、データに1つも触れずに手に入る。
ルール3: 直す前に全findingsを仕分ける
3つ目のルールは、直す前に仕分けることだ。この手のレポートには不安をあおる行がたくさんあり、全部いっぺんに直したくなる。
REA自身のスキルは、すべての結論を観察、推測、unknownのどれかとして印を付け、evidence IDを添えるよう求めている。見たこと、推測したこと、見えなかったことであり、evidence IDは確かめられるレシートだ。まず外部の人の視点だけですべてのfindingをそう仕分け、ソースを1ファイルも開く前にその版をコミットする。そのあとでソースを読み、各行を本物の漏えい、設計どおり、誤検知のどれかに分ける。
私たちのレポートには15件のfindingがあった。
| Finding | REAが見たもの | 私たちの判定 |
|---|---|---|
| 登録エンドポイント | 制限がなく、どのサイトが呼んでいるかの確認もないため、どのウェブサイトでも訪問者のブラウザに任意のアドレスをうちのリストへ登録させられる | 本物の漏えい、最悪 |
| 無料パックのメールゲート | パック全体がすでに読み込むページの中にある。ブラウザのコンソールで1行実行するとゲートが消え、リーダーモードでも本文が見える | 設計どおり |
| ソースマップ、キー、クッキー | バンドルにはなく、クッキーもどこにもない | 良いニュース |
ゲートが設計どおりなのは、無料パックが意図的に無料だからだ。壊れたフォームが無料ページを隠してはいけない、と私たち自身のコードにも書いてある。
限界はunknownの列だ。REAはサーバーが何をしているかを見られないので、その行はサーバーのコードを読んで決着をつける。
ルール4: バンドルは設定を運んでいる
4つ目のルールは、バンドルが何を運んでいるかについてだ。共有された設定ファイルが、知らないうちにすべての訪問者へ届くことがある。
仕組みはこうだ。設定を1つのヘルパーでインポートし、2つの小さなインタラクティブなコンポーネントがそのヘルパーを使う。コードをブラウザが受け取るファイルにまとめるツールであるバンドラーには、それらがどのキーを必要とするかがわからないので、全部を出荷してしまう。
REAが私たちのJavaScriptで見つけたのが、まさにそれだった。サイト設定全体が1つのファイルに入っていて、メーリングリストのID、ビルドフォルダ、私たちの動画のコメントに返信するbotの上限まで含まれていた。botが1日に送る返信の数は100件で、安全スイッチが作動するエラーの数まで書かれていた。それを取り込んだ2つのコンポーネントが読んでいたのは、サイト名と言語のリストだけだった。
ルールは、出荷したJavaScriptの中から自分の設定キーを検索し、クライアントコンポーネントには読むフィールドだけを渡すこと。私たちのサンドボックスでは、エージェントが設定を、そのフィールドだけを持つ小さなブラウザ用の版に分け、残りはサーバー側に置いた。サーバー用のキーが出荷ファイルに再び現れたらビルドを失敗させる手順も足したので、元に戻ることはない。
パスワードではなかったが、そのファイルの中身はすべて公開になる。だから秘密はサーバー変数にだけ置く。
ルール5: 開いているエンドポイントにはブレーキを
5つ目のルールは、私たちの本物の漏えいを塞いだもので、公開フォームから有料サービスを呼ぶときはいつでも当てはまる。メールリスト、AIモデル、SMSゲートウェイなどだ。午後に書いた小さなサーバー関数を通して呼ぶことが多い。うちの関数はメールアドレスを受け取り、そのままメーリングリストに渡していて、ほかのどのウェブサイトでも訪問者のブラウザからそれを送らせられた。
セキュリティ界のチェックリストははっきり言っている。アクセス制御は、攻撃者が変更できないコード、つまりサーバーの上でだけ有効だ。だからそういうエンドポイントすべてにブレーキを付ける。
- Originチェック。 Originヘッダーは、ブラウザがリクエストにどのサイトから来たかを示すために押すスタンプだ。別のウェブサイトのフォームは拒否される。
- レート制限。 1人の訪問者が短い時間に送れるリクエスト数の上限。
- サーバーで確認する同意。 チェックを入れたボックスの状態が、実際にリクエストと一緒に届く。
私たちのサンドボックスでは、エージェントがそのすべてをWorkerに書き込んだ。Workerは、訪問時にページの手前で動く小さな関数だ。そのあと偽のメーリングサービスに対してテストし、本物には一度も向けず、すべてのリクエストが想定どおりの場所で拒否された。違うサイトから送れば拒否され、1分間に6回目のリクエストも拒否され、同意がなければ弾かれる。
限界は、スクリプトならOriginのスタンプを偽装できることと、レート制限が場所ごとに数えることだ。それに対する本当の修正は、メールによる二重確認になる。
ルール6: 再実行して、手で確認して、PRを出す
6つ目で最後のルールは、修正を証明することだ。緑のチェックマークの壁が並ぶときこそ、人は見るのをやめるからだ。REAをデスクトップアプリで試したある開発者は、HackerNoonに、アプリに実在するエントリーポイントを見逃したと書いた。
だから、修正したビルドで同じREAの手順をもう一度実行し、各修正をターミナルから手で確認し、それからやっとプルリクエストを開く。
修正したビルドでは、以前すり抜けていた登録フォームへのリクエストが拒否される。サーバーのキーはすべての出荷ファイルから消え、セキュリティヘッダーも付き、Workerのテストは失敗から合格に変わった。無料パックのゲートは開いたままだった。それが私たちの決定で、レポートはその旨を各行の横に書いている。
そのあとエージェントがプルリクエストを開いた。レポートが入っているのは、プロンプトで頼んだからにすぎない。Kosukeが作るテストのチェックリストはセッションの中に残り、プルリクエスト自体には何も投稿されなかった。レビュアーがGitHubしか読まないなら、修正前と修正後のレポートは自分でプルリクエストに入れよう。
そのあと同じ変更を自分たちのコードに取り込んだ。次のサイトのデプロイで本番に出る。
結論: REAを自分に向けるべきとき
今回の一連の作業は、使い捨てサンドボックスから稼働中の自社サイトにREAを向け、すべてのfindingを仕分け、本物の漏えいを直し、もう一度監査し、プルリクエストとして出荷するというものだった。すべてを正当化した発見は最初のものだ。どのウェブサイトでも、誰のアドレスでもうちの登録フォームに入れられた。
公開フォームや有料サービスが裏にあるものを公開する前にこの監査を行い、出荷内容を変えるたびにもう一度行おう。自分のものではないソフトには使わない。REA自身の免責事項が、自分が所有するか、調べる権限があるソフトに限っているからだ。そしてサーバーのコードを読む代わりにはならない。unknownが潜んでいるのがまさにそこだからだ。
1つだけ守るなら、これを守ってほしい。自分に向けて、箱の中で動かし、仕分けたものだけを直す。
実際のプロンプト、仕分け表、出荷したWorkerの修正は、この動画の無料キットに入っている。
AIDive