---
title: "vibe codingのセキュリティリスク：再現した5つの穴"
description: "vibe codingで作ったアプリで何が壊れるのか。3つの調査の数字と、ローカルのSupabaseで再現した5つのアクセスの穴、そして自分のアプリの確認方法を紹介します。"
url: "https://madsalt.tech/ja/blog/vibe-coding-security-risks/"
author: "Denys Zaichenko"
language: "ja"
published: 2026-10-24
---

# vibe codingのセキュリティリスク：再現した5つの穴

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](https://arxiv.org/abs/2606.23130)、2026年6月                                                           | Claude CodeとLovableで作られた公開済みアプリ200件を、手作業とエージェントで監査 | 200件中182件（91%）に少なくとも1つの脆弱性があった。1,186件の指摘のうち65.77%がCriticalまたはHigh。アクセス制御の不備が最大のカテゴリで、アプリの64%にあった |
| [Escape](https://escape.tech/blog/methodology-how-we-discovered-vulnerabilities-apps-built-with-vibe-coding/)、2025年10月                  | Lovable、Base44、Create.xyzなどの公開アプリ5,600件を、パッシブスキャン          | 影響の大きい脆弱性2,000件超、露出したシークレット400件超、個人データの露出175件。主な原因は権限の設定ミスで、特にSupabaseのRLS                               |
| [Veracode GenAI Code Security Report](https://www.veracode.com/resources/analyst-reports/2026-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つだけ条件を変えました。

![公開キー1つで1つのテーブルから取れたもの。ローカルのSupabase、偽の注文3行、リクエストは各1回。RLSなしのテーブル：Publishable key → orders、RLSオフ → 3行中3行、RLSオン、ポリシーはまだなし：Publishable key → orders、RLSオン → 0行、ポリシー using (true)：Publishable key → using (true) → 3行中3行、security_invokerなしのビュー：Publishable key → order_summaryビュー → 3行中3行、ブラウザのコード内のsecret key：Secret key → BYPASSRLS → 3行中3行。](https://madsalt.tech/charts/ja/vibe-coding-security-risks.svg)

*図1. ローカルのSupabaseスタック（Postgres 17.6、PostgREST 14.14）での私の再現、2026年10月23日。*

| 設定                                   | 公開キーで取れたもの                     | 理由                                                                        |
| -------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------- |
| 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日](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically)から、既存プロジェクトの新しいテーブルは、Data APIへ自動でgrantされなくなります。私のスタックでは、grantのないテーブルが、足りない`GRANT`を示すヒント付きで`42501 permission denied`を返しました。これで新しいテーブルについては上の表の1行目が止まりますが、残りの4行や、すでにあるテーブルは止まりません。

## データベース以外で、ほかに何が壊れる？

同じ調査が挙げているリスクには、RLSと関係ないものもあります。

- **バンドルの中のシークレット。** Escapeは、OpenAIのキーや決済の管理用キーを含む、400件超のシークレットの露出を見つけました。ブラウザに送られるものは、すべて公開されています。
- **Reactの中だけのルートガード。** サインインしていないユーザーをリダイレクトするページでも、その裏のAPIは誰にでも応答します。
- **作動しないレート制限。** 私がプローブしたホスト版のSupabaseプロジェクトでは、Edge Functionのメモリ上のカウンターが、リクエストのたびにリセットされました。これは[Lovableアプリのセキュリティチェックリスト](https://madsalt.tech/ja/blog/lovable-app-security-checklist/)にまとめています。
- **古いライブラリ。** Escapeは、公開アセットに脆弱なJavaScriptライブラリのインスタンスが254件あることを数えました。多くはテンプレートから引き継がれたものです。

## vibe codingで作ったアプリをどう確認する？

1. アプリを開き、DevTools → Networkで`/rest/v1/`へのリクエストを探します。1つをcURLとしてコピーし、`Authorization`ヘッダーを消して`apikey`は残し、実行します。データが返れば、誰にでも返ります。
2. ビルド済みのJavaScriptから`sb_secret_`と`service_role`を検索します。見つかったら、今日ローテーションすべきキーです。
3. 無料の[Supabase セキュリティチェック](https://madsalt.tech/ja/tools/supabase-security-check/)を実行します。プロジェクトのカタログを読み取り、46のルールのうち「公開されたテーブルで RLS が無効」「すべての行を許可するポリシー」「RLS を迂回するビュー」「新しいオブジェクトを API に開くデフォルト権限」を指摘します。上の表の最初の4行に当たります。
4. 2社の2人のユーザーでテストします。これはスキャナーが代わりにやってくれない唯一のテストです。私のやり方は[Lovable向けチェックリスト](https://madsalt.tech/ja/blog/lovable-app-security-checklist/)にあり、[Supabase RLSのテスト方法](https://madsalt.tech/ja/blog/how-to-test-supabase-rls/)では、権限画面のある本番アプリでの手法を紹介しています。

```bash
curl 'https://<project>.supabase.co/rest/v1/orders?select=*' \
  -H 'apikey: <the publishable key from your page>'
```

## これが示していないこと

私の再現は、ローカルスタック上の1つのテーブルで、仕組みを1つずつ見せるために作ったものです。実在のアプリのスキャンではありません。有病率の数字は3つの調査のもので、それぞれ標本も方法も異なり、上にリンクがあります。そして、この5つの確認で問題がなくても、アプリが安全になるわけではありません。値がないときに通してしまうガードのようなロジックのバグには、別のテストが要ります。その1つは[権限チェックを飛ばしたNULL](https://madsalt.tech/ja/notes/plpgsql-if-not-null-fails-open/)にあります。

AIツールでアプリを作りましたか？

まず何を確認するか、情報交換できれば嬉しいです。売り込みはありません。

[お問い合わせ](https://madsalt.tech/ja/#contact)
