TL;DR
AIが書くコードは、たいてい動きます。壊れているのは、誰がデータに届くかのほうです。2026年に公開済みのvibe codingアプリ200件を監査した調査では、91%に少なくとも1つの脆弱性があり、最大のグループはアクセス制御の不備でした。私はそのアクセスの穴のうち5つを、ローカルのSupabaseスタックで再現しました。公開キーだけで、RLSのないテーブル、常に真になるポリシー、ビュー、漏えいしたsecret keyが、それぞれ3行中3行すべてを返しました。まず自分のアプリでこれらを確認してください。
Denysです。フルスタック・AIエンジニアです。Lovable、Bolt、Cursor、Claude Codeで作られたアプリを直していて、そのほとんどはSupabaseで動いています。この記事では、vibe codingのセキュリティについて公開されている調査が何を言っているかと、よくある間違いをわざと作り直して見えたことをまとめます。
vibe codingのセキュリティリスクとは?
主なリスクは、アクセス制御の不備です。訪問者を止めるはずのルールがない、緩すぎる、あるいは迂回されているために、誰でもデータを読んだり変更したりできる状態を指します。その次にインジェクションと弱い認証が続きます。3つの独立した調査が同じ方向を示しています。
| 調査 | 何をテストしたか | 何が見つかったか |
|---|---|---|
| Deng、Fan、Meng、arXiv 2606.23130、2026年6月 | Claude CodeとLovableで作られた公開済みアプリ200件を、手作業とエージェントで監査 | 200件中182件(91%)に少なくとも1つの脆弱性があった。1,186件の指摘のうち65.77%がCriticalまたはHigh。アクセス制御の不備が最大のカテゴリで、アプリの64%にあった |
| Escape、2025年10月 | Lovable、Base44、Create.xyzなどの公開アプリ5,600件を、パッシブスキャン | 影響の大きい脆弱性2,000件超、露出したシークレット400件超、個人データの露出175件。主な原因は権限の設定ミスで、特にSupabaseのRLS |
| Veracode GenAI Code Security Report、2025年と2026年 | 100以上のモデルに80のコーディング課題を与えた | 2025年に安全なコードを出したのは課題の55%だけ。2026年の平均合格率は56%で、モデルの大きさや年が変わっても横ばい |
調査ごとに測っているものが違うので、パーセンテージを足して1つの数字にはできません。共通しているのは形です。コードは動き、穴は信頼境界にあります。
どんな穴を再現した?
ローカルのSupabaseスタック(CLI 2.109.1、Postgres 17.6、PostgREST 14.14)に、偽の顧客3行を持つテーブルordersを1つ用意しました。そのうえで、すべてのSupabaseフロントエンドが配布しているpublishable key(公開用キー)を使い、ブラウザと同じようにData APIを呼び出して、毎回1つだけ条件を変えました。
| 設定 | 公開キーで取れたもの | 理由 |
|---|---|---|
| RLSなしのテーブル | 3行すべて。INSERTは201 Createdを返した |
デフォルトのgrantでanonが読み書きでき、行を絞るものがない |
| RLSオン、ポリシーなし | []、空のリスト |
ポリシーのないRLSは、anonとauthenticatedにすべてを拒否する |
ポリシーusing (true) |
3行すべて | ポリシーがあるのでテーブルは守られて見えるが、すべての行を許可している |
| 保護したテーブルの上のビュー | 3行すべて | ビューはsecurity_invoker = trueがない限り所有者の権限で動く。付けると[] |
| フロントエンドのコードにあるsecret key | 3行すべて | secret keyはservice_roleに対応し、service_roleはBYPASSRLSを持つ |
2行目が危険な瞬間です。RLSがオンになり、アプリには空のリストが出るので、壊れたように見えます。それを「直す」いちばん早いプロンプトは、すべてを許可するポリシーで、それが3行目です。エラーが出て、アクセスを広げる修正で消す。この流れが、vibe codingのアプリで私が最もよく見るパターンで、「RLSはオン」だけではほとんど何も言えない理由です。
AIが書いたコードがアクセス制御で失敗するのはなぜ?
エージェントは、動くコードで評価されます。空のリストや401はバグに見え、それを消す修正は、アクセスを開く修正であることがよくあります。arXivの調査は、1,186件の指摘を8つの繰り返し現れる失敗モードに分類しています。エージェントのメモリ、目的、知識の欠陥として整理されており、プロンプトを工夫すると穴の数は減るものの、なくならなかったと報告しています。
2つ目の理由はアーキテクチャです。LovableやBoltのアプリは、通常、自前のバックエンドを持ちません。ブラウザがData APIを通してデータベースと直接やり取りします。顧客データを守るルールはすべて、grant、ポリシー、関数としてPostgresの中にある必要があり、オーナーとしてサインインしているアプリのプレビューには、そのどれも映りません。Supabaseはここでデフォルトを1つ変えます。2026年10月30日から、既存プロジェクトの新しいテーブルは、Data APIへ自動でgrantされなくなります。私のスタックでは、grantのないテーブルが、足りないGRANTを示すヒント付きで42501 permission deniedを返しました。これで新しいテーブルについては上の表の1行目が止まりますが、残りの4行や、すでにあるテーブルは止まりません。
データベース以外で、ほかに何が壊れる?
同じ調査が挙げているリスクには、RLSと関係ないものもあります。
- バンドルの中のシークレット。 Escapeは、OpenAIのキーや決済の管理用キーを含む、400件超のシークレットの露出を見つけました。ブラウザに送られるものは、すべて公開されています。
- Reactの中だけのルートガード。 サインインしていないユーザーをリダイレクトするページでも、その裏のAPIは誰にでも応答します。
- 作動しないレート制限。 私がプローブしたホスト版のSupabaseプロジェクトでは、Edge Functionのメモリ上のカウンターが、リクエストのたびにリセットされました。これはLovableアプリのセキュリティチェックリストにまとめています。
- 古いライブラリ。 Escapeは、公開アセットに脆弱なJavaScriptライブラリのインスタンスが254件あることを数えました。多くはテンプレートから引き継がれたものです。
vibe codingで作ったアプリをどう確認する?
- アプリを開き、DevTools → Networkで
/rest/v1/へのリクエストを探します。1つをcURLとしてコピーし、Authorizationヘッダーを消してapikeyは残し、実行します。データが返れば、誰にでも返ります。 - ビルド済みのJavaScriptから
sb_secret_とservice_roleを検索します。見つかったら、今日ローテーションすべきキーです。 - 無料のSupabase セキュリティチェックを実行します。プロジェクトのカタログを読み取り、46のルールのうち「公開されたテーブルで RLS が無効」「すべての行を許可するポリシー」「RLS を迂回するビュー」「新しいオブジェクトを API に開くデフォルト権限」を指摘します。上の表の最初の4行に当たります。
- 2社の2人のユーザーでテストします。これはスキャナーが代わりにやってくれない唯一のテストです。私のやり方はLovable向けチェックリストにあり、Supabase RLSのテスト方法では、権限画面のある本番アプリでの手法を紹介しています。
curl 'https://<project>.supabase.co/rest/v1/orders?select=*' \
-H 'apikey: <the publishable key from your page>'
これが示していないこと
私の再現は、ローカルスタック上の1つのテーブルで、仕組みを1つずつ見せるために作ったものです。実在のアプリのスキャンではありません。有病率の数字は3つの調査のもので、それぞれ標本も方法も異なり、上にリンクがあります。そして、この5つの確認で問題がなくても、アプリが安全になるわけではありません。値がないときに通してしまうガードのようなロジックのバグには、別のテストが要ります。その1つは権限チェックを飛ばしたNULLにあります。