「AIが書いたコードにセキュリティの問題なんてあるの?」——あります。しかも、あなたが思っている以上に深刻です。
セキュリティ企業の調査によると、AI生成コードの約48%にセキュリティ脆弱性が含まれています。さらに厄介なのは、開発者の75%以上が「AIが書いたコードは人間より安全」と誤認しているというデータです。この認知のギャップこそが、バイブコーディング時代の最大のリスクです。
この記事では、AIが実際に生成する脆弱なコードの具体例と、AIコーディングツールにセキュリティガードレールを組み込む方法を解説します。概念論ではなく、今日から使えるチェックリストを提供します。
バイブコーディングのセキュリティ、何が問題なのか
バイブコーディングとは、自然言語でAIに指示を出してコードを生成するスタイルです。プロトタイプの爆速開発には最適ですが、セキュリティ面では構造的な問題を抱えています。
問題の本質は「動くこと」と「安全であること」の混同です。
AIが生成するコードは、構文的にはほぼ完璧です。コンパイルも通り、期待どおりに動作します。しかし「動く」ことと「安全である」ことはまったく別の話です。ある研究では、AIコーディングツールを使った開発者は、使わなかった開発者より有意にセキュリティの低いコードを書いたと報告されています。しかも、本人は安全なコードを書いたと確信していました。
数字で見るリスク
実態を理解するために、2025〜2026年の主要な調査データを確認しましょう。
- AI生成コードの86%がXSS防御に失敗、88%がログインジェクションに脆弱
- AIが推奨するパッケージの約20%が実在しない(パッケージ幻覚)
- AI支援コミットの秘密情報漏洩率は**3.2%**で、通常の約2倍
- 2025年にGitHub公開コミットに追加されたハードコード秘密情報は約2,900万件(前年比34%増)
AIが生成する7つの危険パターン
概念的な説明だけでは実感が湧かないので、AIが実際に生成しがちな脆弱パターンをコード付きで見ていきます。
1. ハードコードされた認証情報
AIに「データベース接続を設定して」と頼むと、こういうコードが出てくることがあります。
// NG: AIが生成しがちなパターン
const dbConfig = {
host: "localhost",
user: "admin",
password: "supersecret123",
database: "myapp",
};
「後で環境変数に置き換えればいいや」と思うでしょう。しかし、このコードがそのままコミットされてGitHubにプッシュされるケースが後を絶ちません。
// OK: 環境変数で管理
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
};
if (!dbConfig.password) {
throw new Error("DB_PASSWORD is not set");
}
2. SQLインジェクション
AIは文字列結合によるSQLクエリを平気で生成します。
// NG: 文字列テンプレートでSQLを組み立てている
app.get("/users", async (req, res) => {
const { name } = req.query;
const result = await db.query(`SELECT * FROM users WHERE name = '${name}'`);
res.json(result.rows);
});
攻撃者が name に '; DROP TABLE users; -- を渡せばテーブルが消えます。
// OK: パラメータ化クエリを使う
app.get("/users", async (req, res) => {
const { name } = req.query;
const result = await db.query("SELECT * FROM users WHERE name = $1", [name]);
res.json(result.rows);
});
3. BaaS の権限設定不備
これはバイブコーディング特有の最も深刻な問題です。AIに「SupabaseでCRUD APIを作って」と指示すると、動くコードは生成されます。しかし、Row Level Security(RLS)の設定は生成されないことがほとんどです。
2026年2月、あるAIエージェント向けSNSで150万件以上のAPIキーとユーザーデータが露出した事件がありました。原因はまさにこのパターンで、クライアントサイドにAPIキーが露出し、RLSが未設定でした。
-- 最低限必要なRLSの設定例
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can only read own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can only insert own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
私のポジション: BaaSを使うバイブコーディングプロジェクトでは、RLSの設定を最初のタスクにすべきです。機能実装より先にセキュリティの骨格を作る。この順序を守らないと、後から修正するのは数倍のコストがかかります。
4. XSSの未対策
AIはReactやVueでHTMLを直接描画するAPIを気軽に使います。
// NG: ユーザー入力をそのままHTMLとして描画
function Comment({ content }: { content: string }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
// OK: DOMPurify等でサニタイズしてからHTMLとして描画
import DOMPurify from "dompurify";
function Comment({ content }: { content: string }) {
const sanitized = DOMPurify.sanitize(content);
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}
5. 認証・認可ロジックの省略
AIに「ユーザープロフィール編集APIを作って」と頼むと、認証チェックが抜けたAPIが出てくることがあります。
// NG: 誰でも任意のユーザー情報を更新できてしまう
app.put("/api/users/:id", async (req, res) => {
const { id } = req.params;
await db.query("UPDATE users SET name = $1 WHERE id = $2", [
req.body.name,
id,
]);
res.json({ success: true });
});
// OK: 認証済みユーザーが自分のデータだけ更新できる
app.put("/api/users/:id", requireAuth, async (req, res) => {
const { id } = req.params;
if (req.user.id !== id) {
return res.status(403).json({ error: "Forbidden" });
}
await db.query("UPDATE users SET name = $1 WHERE id = $2", [
req.body.name,
id,
]);
res.json({ success: true });
});
6. 秘密情報の.envファイル自動読み込み
これはツール側の問題です。一部のAIコーディングツールは、プロジェクトの .env ファイルを自動的にコンテキストとして読み込みます。つまり、APIキーやデータベースパスワードがAIの処理に含まれる可能性があります。
対策:
.envをコンテキストから除外する設定を確認する- シークレット管理ツール(環境変数マネージャー等)を使い、
.envファイル自体を最小限にする - 重要な認証情報はシークレットマネージャーで管理し、実行時に注入する
7. パッケージ幻覚(Slopsquatting)
AIが存在しないパッケージ名を推奨し、それが繰り返し同じ名前で出現するという問題です。攻撃者がその名前でマルウェアパッケージを登録すれば、バイブコーディングで npm install した開発者がそのまま被害に遭います。
# AIが推奨したパッケージを鵜呑みにしない
# まずnpmレジストリで実在確認
npm info <package-name>
# ダウンロード数・メンテナンス状況を確認
npm view <package-name> time downloads
CLAUDE.mdにセキュリティガードレールを組み込む
AIが生成するコードの品質は、指示の品質に大きく依存します。AIコーディングツールの設定ファイルにセキュリティルールを明記しておけば、生成されるコードの安全性は大幅に向上します。
以下は、私が実際にプロジェクトのCLAUDE.mdに記載しているセキュリティセクションの例です。CLAUDE.mdの基本的な書き方や設計パターンについては「CLAUDE.md の書き方 設計パターン集」も参考にしてください。
## セキュリティ規約
### 絶対禁止事項
- ハードコードされた認証情報(パスワード、APIキー、トークン)
- 文字列結合によるSQLクエリの構築
- ユーザー入力をサニタイズなしでHTMLに出力
### 必須事項
- すべてのAPIエンドポイントに認証ミドルウェアを適用
- ユーザー入力は必ずバリデーション(zodなど)を通す
- データベースアクセスはパラメータ化クエリのみ
- 環境変数が未設定の場合はアプリケーション起動時にエラーで停止
### 依存関係
- 新しいパッケージ追加前にnpmレジストリで実在確認
- 週間ダウンロード数が1,000未満のパッケージは使用しない
- `npm audit` で重大な脆弱性がある依存関係は使用禁止
この設定を入れてから、AIが生成するコードでハードコードされた認証情報やサニタイズ漏れは激減しました。完全にゼロにはなりませんが、設定なしの場合とは雲泥の差です。
実践チェックリスト
バイブコーディングでアプリを作る際に、最低限確認すべき項目をまとめます。
コード生成時(毎回)
- 認証情報がハードコードされていないか
- SQLクエリがパラメータ化されているか
- ユーザー入力にバリデーションとサニタイズが適用されているか
- APIエンドポイントに認証・認可チェックがあるか
- エラーメッセージに内部情報(スタックトレース、DB構造)が含まれていないか
プロジェクト設定時(初回)
- CLAUDE.md / .cursorrules にセキュリティ規約を記載
-
.envがコンテキストに含まれない設定になっているか確認 -
.gitignoreに.envが含まれているか - BaaSを使う場合、RLS / セキュリティルールを最初に設定
- CI/CDにセキュリティスキャン(
npm audit、SAST)を組み込み
デプロイ前(必須)
-
npm auditを実行し、重大な脆弱性がないか確認 - シークレットスキャン(gitguardian、gitleaks等)を実行
- 認証フローの手動テスト(他ユーザーのデータにアクセスできないか)
- HTTPSが有効で、セキュリティヘッダー(CSP、X-Frame-Options等)が設定されているか
よくある誤解を正す
「AIが書いたコードだから安全」 — これが最も危険な誤解です。AIは構文的に正しいコードは得意ですが、セキュリティのコンテキスト(誰がアクセスするか、どんな入力が来るか)を十分に考慮しないことが多いです。
「プロトタイプだからセキュリティは後回しでいい」 — プロトタイプがそのまま本番になるのがバイブコーディングの常です。「後で直す」の「後」は来ません。最初から設定する方が、結局は早いです。
「セキュリティツールが全部検出してくれる」 — 標準的なSAST/DASTツールでも、AI特有の脆弱性パターンの40〜60%しか検出できないという報告があります。ツールは補助であり、開発者の理解に代わるものではありません。
まとめ: バイブコーディングを安全に使うために
バイブコーディングそのものが悪いわけではありません。問題は、セキュリティの責任がAIにあると錯覚することです。
私のポジションは明確です: AIが生成したコードは、ジュニアエンジニアが書いたコードと同じレベルでレビューすべきです。動くかどうかだけでなく、安全かどうかを確認する。この一手間が、150万件のAPIキー漏洩のような事態を防ぎます。
具体的には:
- CLAUDE.mdにセキュリティ規約を書く — AIへの指示品質がコード品質を決める
- Hooksでガードレールを強制する — CLAUDE.mdはアドバイス、Hooksは確実に実行されるガードレール
- BaaSのRLS設定を機能実装より先にやる — 順序を守る
- デプロイ前にチェックリストを通す — 自動化できるものはCI/CDに組み込む
AIは最高のコーディングアシスタントですが、セキュリティの最終責任者は常にあなたです。
組織でAIコーディングツールを導入する際のルール設計やガバナンスの全体像は、AIの組織利用ガイドで整理しています。開発部門向けに一段具体化した雛形が必要なら、AIコーディングツールの社内ガイドラインも合わせて確認してください。