Lovable コードベース監査: セキュリティ問題、RLS ギャップ、API キー漏洩
先月、あるクライアントが私たちのところに来ました。Lovableで生成されたアプリケーションが既に本番環境で稼働していて、有料顧客を抱えていたのです。彼らはいくつかの機能を追加し、「少し整理してほしい」と言っていました。初期コードベース監査で見つけたものは...啓発的でした。クライアント側のコードに露出したAPIキー。ユーザーデータを保有するテーブルに欠けているRow Level Securityポリシー。サーバー側の検証がないSupabaseの直接呼び出し。そしてこれは一度限りではなく、今では6つの異なるLovableプロジェクトを監査しており、パターンは驚くほど一貫しています。
はっきりしておきたいのは、Lovableはプロトタイピング用の優れたツールということです。自然言語プロンプトから動作するUIを生成する速度は本当に驚異的です。ですが「動作するプロトタイプ」と「本番対応アプリケーション」の間には大きなギャップがあり、そのギャップはほとんどの非技術系創業者さえも見つけ方を知らないセキュリティ脆弱性で埋め尽くされています。
この記事は、複数のLovableコードベース監査で見つけたものの技術的内訳です。Lovableで何かを構築し、実ユーザーのお金またはデータを扱っている場合、この記事を読む必要があります。
目次
- Lovableが実際に生成するもの
- APIキーの問題
- Row Level Security:サイレントキラー
- 認証と認可のギャップ
- クライアント側のビジネスロジック露出
- Supabase Edge Functions:何が不足しているのか
- 見つけた一般的な脆弱性パターン
- 独自のLovableプロジェクトを監査する方法
- 再構築する時と修復する時
- FAQ

Lovableが実際に生成するもの
Lovableはreactアプリケーション(通常Viteを使用)をTailwind CSSとshadcn/uiコンポーネント、Supabaseバックエンドに接続して生成します。スタック自体は堅実です。私たちもNext.js開発の仕事で定期的にこれらのツールを使って構築しています。問題はテクノロジーの選択ではなく、それらが一体どのように配線されているかです。
典型的なLovableプロジェクト構造はこんな感じです:
src/
├── components/
│ ├── ui/ # shadcnコンポーネント
│ ├── Dashboard.tsx
│ ├── Settings.tsx
│ └── ...
├── integrations/
│ └── supabase/
│ ├── client.ts # ← ここから問題が始まる
│ └── types.ts
├── pages/
├── hooks/
└── lib/
生成されるコードはクリーンで読みやすいです。その点はLovableを褒めてあげます。しかし、読みやすさはセキュリティと同義ではありません。アーキテクチャはデモには良いけれど本番環境には危険な決定を下しています。
具体的に見てみましょう。
APIキーの問題
私たちが監査したすべてのLovableプロジェクトには、Supabaseの認証情報がクライアント側のコードに含まれています。今、Supabase擁護派が出てくる前に説明します:はい、anonキーはpublicであることが設計されています。Supabaseのドキュメントはこれを明確に述べています。anonキーはクライアント側のコードで使用することを意図しており、セキュリティはRow Level Securityポリシーを通じて強制されることになっています。
しかしここで悪い部分が出てきます。
私たちが監査した6つのプロジェクトのうち3つで、Supabaseのservice_roleキーが以下のいずれかを行っていました:
- ユーティリティファイルに直接ハードコードされている
- GitHubリポジトリにコミットされた
.envファイルに保存されている - 認証なしでアクセスできるSupabase Edge Functionで参照されている
service_roleキーはすべてのRLSポリシーをバイパスします。誰かがそれを手に入れたら、データベース全体への完全な読み書きアクセスが可能になります。すべてのテーブル。すべての行。すべてのユーザーのデータ。
// Lovableプロジェクトで見つけた実際のパターン(キーは編集済み)
import { createClient } from '@supabase/supabase-js'
// これはlib/admin.tsというファイルにあり
// クライアント側のコンポーネントからインポートされて使用されていました
const supabaseAdmin = createClient(
'https://xxxxx.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // service_roleキー!
)
これはLovableによって直接生成されませんでした。創業者が管理者機能が必要になったときにLovableに「管理パネルを追加して」と依頼して追加されました。Lovableは従い、サーバー側とクライアント側のセキュリティ境界の概念がないため、キーを便利な場所に置きました。
anonキーだけが露出している場合であっても(意図どおり)、RLSが正しく設定されていないとセキュリティモデルは崩壊します。これは大きなものです。
Row Level Security:サイレントキラー
Row Level Security(RLS)はSupabaseがデータを保護するために使用する主要なセキュリティメカニズムです。正しく設定されると、クライアントからどのようなAPI呼び出しが行われるかに関わらず、ユーザーが自分のデータのみにアクセスできることを保証します。
6つのLovableプロジェクトを監査したときの結果:
| プロジェクト | テーブル合計 | RLS有効なテーブル | 正しいRLSポリシーを持つテーブル | 露出した機密データ |
|---|---|---|---|---|
| SaaSダッシュボード | 14 | 6 | 3 | ユーザーPII、請求データ |
| Eコマースアプリ | 22 | 10 | 4 | 注文履歴、アドレス |
| ヘルストラッカー | 11 | 4 | 2 | 健康記録、投薬 |
| プロジェクトマネージャー | 18 | 8 | 5 | クライアントデータ、ドキュメント |
| 予約プラットフォーム | 16 | 7 | 3 | 連絡先情報、スケジュール |
| CRMツール | 20 | 9 | 4 | 顧客データ、ノート |
もう一度読んでください。実際の投薬と健康情報を保存していたヘルストラッカーアプリで、11のテーブルのうち2つだけが正しいRLSポリシーを持っていました。anonキーを持っている人なら(公開されていることを覚えていますか)すべてのユーザーの健康記録をクエリできます。
見つける最も一般的なRLS障害:
ポリシーが完全に欠けている
LovableはしばしばRLSを有効にせずにテーブルを作成します。Supabaseではデフォルトで新しいテーブルのRLSは無効になっているため、anonキーを持っているすべてのユーザーがすべてのデータを読み取ることができます。
-- 見つけるもの:RLSが有効になっていない
CREATE TABLE public.user_profiles (
id UUID REFERENCES auth.users,
full_name TEXT,
email TEXT,
phone TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- ALTER TABLE ... ENABLE ROW LEVEL SECURITY;がない
-- ポリシーが定義されていない
過度に許容的なポリシー
Lovableがすべての場合にRLSを追加するとき、ポリシーはしばしば広すぎます:
-- 一般的なLovable生成ポリシー
CREATE POLICY "Users can view all profiles"
ON public.user_profiles
FOR SELECT
USING (true); -- これはすべての認証ユーザーがすべてのプロフィールを読むことを許可する
修正は以下のようになるべきです:
-- それはどうあるべきか
CREATE POLICY "Users can view own profile"
ON public.user_profiles
FOR SELECT
USING (auth.uid() = id);
欠けているDELETEおよびUPDATEポリシー
SELECT ポリシーが正しい場合でも、INSERT/UPDATE/DELETEポリシーは頻繁に欠けているか間違っています。任意の認証ユーザーが他のユーザーのプロフィールを更新できるケースを見つけました。

認証と認可のギャップ
Lovableは基本的な認証を適切に処理しています。Supabase Authをメール/パスワードまたはソーシャルログインで設定し、ログイン/サインアップフローは一般的にうまく機能します。しかし認証(あなたは誰ですか)と認可(あなたは何ができますか)は異なるものです。
認可層はほぼ常に不完全またはまったく存在しません。
マルチテナントSaaSアプリケーションを考えてください。ユーザーは組織に属しています。彼らは彼らの組織からのデータだけを見るべきです。彼らは異なるロール(管理者、メンバー、閲覧者)を持つかもしれません。Lovableはこれらのどれも生成しません。
典型的に見つけるもの:
// Lovable生成データ取得
const { data: projects } = await supabase
.from('projects')
.select('*')
// organization_idのフィルターがない
// ユーザーのロールまたは権限のチェックがない
修正はデータベースレベル(RLS)とアプリケーションレベルの両方の変更が必要です。ユーザーを組織にマッピングするロール付きmembershipsテーブル、メンバーシップをチェックするRLSポリシー、適切にフィルタリングするアプリケーションコードが必要です。
これは事後的に付け加えるのが難しい種類のアーキテクチャ作業です。すべてのクエリ、すべてのコンポーネント、すべてのページに影響します。Lovableでマルチテナント SaaSを構築している場合、これがあなたに最も厳しく当たることになります。
クライアント側のビジネスロジック露出
Lovableは純粋なクライアント側のReactアプリケーションを生成するため、すべてのビジネスロジックはブラウザに存在します。これは以下を意味します:
- 価格計算がブラウザDevToolsで可視化および操作可能
- フィーチャーフラグが異なるサブスクリプション層はクライアント側でチェックされる
- ディスカウントコードと検証ロジックがJavaScriptバンドルにある
- APIレート制限が存在しない(実装するサーバーがない)
見つけたLovable生成SaaSの1つは、価格層チェックが完全にクライアント側でした:
// Lovableプロジェクトのコンポーネントで見つけた
const canAccessFeature = (feature: string) => {
const plan = user?.subscription?.plan
if (plan === 'pro') return true
if (plan === 'basic' && BASIC_FEATURES.includes(feature)) return true
return false
}
ユーザーはブラウザコンソールでこの関数を単に修正することや、このチェックなしにSupabase APIを直接呼び出すことで、基本プランでプロ機能にアクセスできます。データベースには計画ベースのアクセスを強制するポリシーがありませんでした。
これは根本的なアーキテクチャ問題です。ビジネスロジックにはサーバー側の要素が必要です。それはNext.js APIルート、Supabase Edge Functions、別のバックエンドサービスのどれでも良い。ユーザーが改ざんできない場所で操作を検証する何かが必要です。
これがまさにNext.jsやAstroのようなフレームワークを本番SaaSアプリケーションにお勧めする理由です。すぐに使えるサーバー側レンダリングとAPIルートを提供します。
Supabase Edge Functions:何が不足しているのか
いくつかのLovableプロジェクトはSupabase Edge Functionsを特定の操作に使用します。通常はStripe webhook処理やメール送信です。しかし実装にはしばしば問題があります:
入力検証がない:Edge Functionsは形状、型、制約を検証せずに送信されたJSONを受け入れて処理します。
CORSがすべてのオリジンを許可するために設定されている:
// Lovable Edge Functionsの一般的なパターン
const corsHeaders = {
'Access-Control-Allow-Origin': '*', // このエンドポイントを呼び出すことを許可するあらゆるウェブサイト
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
認証チェックがない:関数がJWTトークンを検証しないため、未認証ユーザーはそれを呼び出すことができます。
Stripe webhook署名が検証されていない:2つのプロジェクトでStripe webhookハンドラーはwebhook署名を検証しなかったため、誰もがEndpointに対して偽の支払いイベントを送信することができました。
// 見つけたもの -- 署名検証がない
Deno.serve(async (req) => {
const body = await req.json()
// それがStripeから来たことを検証せずにイベントを直接処理する
if (body.type === 'checkout.session.completed') {
// ユーザーのサブスクリプションを更新
await supabaseAdmin.from('subscriptions').update({
status: 'active',
plan: 'pro'
}).eq('user_id', body.data.object.metadata.user_id)
}
})
これは攻撃者がwebhook URLに対して偽のcheckout.session.completedイベントでPOSTリクエストを送信し、任意のユーザーを無料でproプランにアップグレードできることを意味しています。
見つけた一般的な脆弱性パターン
最も一般的な問題を重大度と頻度でランク付けした要約:
| 脆弱性 | 重大度 | 頻度(6つのうち) | 利用可能性 |
|---|---|---|---|
| 機密テーブルのRLSがない | 重大 | 6/6 | 簡単 -- テーブルをクエリするだけ |
| 過度に許容的なRLSポリシー | 高 | 6/6 | anonキーで簡単 |
| service roleキーの露出 | 重大 | 3/6 | 見つかった場合は自明 |
| Stripe webhookの検証なし | 高 | 4/6 | 中 -- Endpoint URLが必要 |
| クライアント側の認可のみ | 高 | 6/6 | DevToolsで簡単 |
| Edge Functionsで入力検証がない | 中 | 5/6 | 中 |
| Edge Functions上のCORSワイルドカード | 中 | 5/6 | 簡単 |
| localStorageの機密データ | 中 | 4/6 | 物理的アクセスまたはXSS |
| レート制限がない | 中 | 6/6 | 自明 |
| 不安なダイレクトオブジェクト参照 | 高 | 5/6 | 簡単 -- URLのIDを変更 |
独自のLovableプロジェクトを監査する方法
Lovableで実ユーザーデータを扱うものを構築した場合、これらの問題をチェックする方法は以下の通りです。
ステップ1:Supabase RLSステータスを確認
Supabaseダッシュボードに移動 → テーブルエディタ。各テーブルをクリックしてRLSが有効になっているかどうかを確認してください。次に認証 → ポリシーに移動し、各ポリシーを確認します。
またはSQL エディタでこのクエリを実行します:
SELECT
schemaname,
tablename,
rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY tablename;
ユーザーデータを含む任意のテーブルでrowsecurityがfalseの場合、これは重大な問題です。
ステップ2:露出したキーを検索
コードベースで以下を検索してください:
grep -r "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" src/
grep -r "service_role" src/
grep -r "SUPABASE_SERVICE" src/
最初のパターンはSupabase JWTキーの開始を一致させます。src/ディレクトリのどこかでservice_roleキーを見つけた場合、それは直ちに重大な脆弱性です。
ステップ3:RLSポリシーをテスト
2番目のテストユーザーアカウントを作成してください。そのユーザーとしてログインし、ユーザー1のデータにアクセスしてみてください。ブラウザのネットワークタブを確認してください。本来見るべきではないデータを受け取っていますか?
curlで直接テストすることもできます:
curl 'https://YOUR_PROJECT.supabase.co/rest/v1/user_profiles?select=*' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
認証なしてすべてのユーザープロフィールを返す場合、RLSは壊れています。
ステップ4:Edge Functionsをチェック
各Edge Functionを以下についてレビューしてください:
- JWT検証
- 入力検証
- CORS設定
- Webhook署名検証(Stripe/支払いハンドラーの場合)
ステップ5:クライアント側バンドルを検査
npm run buildを実行し、出力を検査してください。ビルドされたJavaScriptでAPIキー、ビジネスロジック、価格データを検索してください。バンドル内のものは何でもユーザーに可視です。
再構築する時と修復する時
これはLovable創業者がこれらの問題が存在することに気づいたら直面する質問です。答えはいくつかの要因に依存します。
修復の場合:
- あなたのアプリに10未満のテーブルがある
- 複雑な認可モデル(マルチテナンシーなし、ロールなし)がない
- コアアーキテクチャ(データモデル、ページ構造)が堅実
- 主にRLSポリシーを追加し、いくつかのロジックをサーバー側に移す必要がある
再構築の場合:
- ロールと権限を持つマルチテナントアーキテクチャが必要
- ビジネスロジックが複雑ですべてがクライアント側
- SEOまたはパフォーマンスのためのサーバー側レンダリングが必要
- Supabaseスキーマに重大な構造問題がある
- スケールがある規模で適切なインフラが必要
修復の場合、通常はすべてのテーブル全体にRLSポリシーを追加し、機密ロジックをEdge Functionsまたはサーバー側レイヤーに移行し、適切な入力検証を実装し、レート制限を追加しています。複雑さに応じて、これは経験を積んだ開発者向けの2~4週間のプロジェクトです。
フルリビルドの場合、ヘッドレスアーキテクチャを適切な関心事の分離で推奨します。初期費用は多くかかりますが、スケールする基盤を提供します。これの概要については価格ページを確認してください。
どのパスが正しいか確かでない場合、簡単な評価を実施できます。コンタクトページからお気軽にご連絡ください。
FAQ
Lovableは本番アプリケーションに使用しても安全ですか?
Lovableは堅実なスタートポイントを生成できますが、実ユーザーがデータをそれに信頼する前に、出力は重大なセキュリティ強化が必要です。生成されるコードは適切なRLSポリシー、サーバー側の検証、認可ロジックが不足しています。足場と考えてください。完成した建物ではなく。あなたは絶対に開発者にレビューさせてコードを保護してから、実ユーザーがそれで信頼を置く必要があります。
Lovableは私のSupabase APIキーを露出させますか?
Supabaseanonキーは意図的に公開されています。設計により、Supabaseのセキュリティモデルはそれを説明しています。問題はLovable(またはプロンプトによってあなた)がクライアント側のコード内にservice_roleキーを配置するときです。anonキーが公開されるのは、RLSポリシーが防弾である場合のみ安全であり、Lovable生成プロジェクトではそれらは通常そうではありません。
Row Level Securityとはなぜ重要ですか?
Row Level Security(RLS)は、ユーザーが読み取り、挿入、更新、または削除できる行を制御するPostgreSQL機能です。RLSなしでは、あなたの公開anonキーを持つ人は誰もあなたのデータベース全体をクエリすることができます。すべてのユーザーのデータ、すべてのプライベートレコード。Supabaseをバックアップしたアプリケーションで最も重要なセキュリティメカニズムであり、Lovableプロジェクトで最も一般的に設定が誤っているものです。
開発者なしで自分自身でLovableセキュリティ問題を修正できますか?
SQLとSupabaseのRLSポリシー構文を理解している場合、Supabaseダッシュボードを使用して基本的なRLSポリシーを自分自身で追加できます。しかし、ポリシーが正しいことを確認する、特にマルチテナンシー、共有リソース、または管理者アクセスのような複雑なシナリオでは経験が必要です。間違ったポリシーはユーザーを自分のデータからロックアウトしたり、すべてを露出させたりする可能性があります。簡単なパーソナルプロジェクトを超える場合、プロフェッショナルの目を取得してください。
私のLovableアプリケーションのデータベースが安全かどうかをチェックするにはどうしたらいいですか?
最速テスト:ブラウザのDevToolsを開き、ネットワークタブに移動し、あなたのアプリが行うSupabase API呼び出しを見てください。apikeyヘッダー値をコピーしてください。次にcurlまたはPostmanを使用してそのキーだけでテーブルをクエリしますが、認証トークンなしです。他のユーザーのデータを取得するか、プライベートであるべきテーブルでデータを取得する場合、RLSは壊れています。
一般的にAI生成コードの最大のセキュリティリスクは何ですか?
AIコード生成器はセキュアにすることではなく、物事が機能することを最適化します。彼らは脅威の風景の精神的なモデルを持っていません。最大のリスクは:露出した秘密、欠けている入力検証、過度に許容的なアクセス制御、サーバー側のセキュリティ境界の不在です。これらはLovableに固有ではありません。同様の問題はCursor、v0、Bolt、他のAIツールからのコードに存在しています。違いはLovableが人々が本番環境に直接デプロイする完全なアプリケーションを生成することです。
Lovableを使用した後、別のバックエンドに切り替えるべきですか?
Supabase自体は良好です。それは適切なセキュリティ機能を持つ堅実なプラットフォームです。問題はLovableがどのように設定するかです。Supabaseを放棄する必要はありません。適切にRLSポリシーを設定し、機密操作をEdge Functionsに移動し、Lovableがスキップしたの認可層を追加する必要があります。インフラストラクチャは良い。設定だけが作業が必要です。
Lovable生成アプリケーションのセキュリティ問題を修正するのにいくらかかりますか?
簡潔な修復の場合、RLSポリシーを追加し、Edge Functionsを保護し、露出したキーを削除し、基本的な入力検証を追加する場合、テーブル数と認可モデルの複雑さに応じて約$3,000~$8,000を見ています。適切なアーキテクチャでのフルリビルドは複雑さに応じて$15,000~$50,000以上を実行します。コアデータモデルが健全な場合、修復パスはほぼ常により費用対効果が高いです。