「AIが書いたコードだから大丈夫」――その思い込みが一番危ない
「自然言語で指示するだけでアプリが完成した」「コードをほとんど読まずにリリースできた」――バイブコーディングを経験した方なら、この感覚をご存知でしょう。Cursor、GitHub Copilot、v0、Bolt.newなどのAIツールを使えば、数時間でWebアプリを動かすことができます。スタートアップ、社内ツール、副業プロジェクト……あらゆる場面でAI主導の開発が当たり前になってきました。
しかし、ここに大きな落とし穴があります。
AIは「動くコード」を生成しますが、「安全なコード」を保証しているわけではありません。
2026年現在、バイブコーディングで作られたシステムの脆弱性診断依頼がセキュリティ業界で急増しています。典型的なパターンは「Cursorで作った社内ツールを外部に公開したら、翌月に不正アクセスされた」「Copilotで書いたAPIにAPIキーがハードコードされていた」というものです。
この記事では、バイブコーディングでシステムを作った方が知っておくべきセキュリティリスクと、自分でできる最初のチェック方法、そして専門家に依頼すべきタイミングを解説します。
本記事は経営者・開発者・情シス担当者を問わず、AIツールで開発したシステムを運用・公開している方を主な対象としています。
バイブコーディングとは何か
バイブコーディング(Vibe Coding)は、2025年2月にAI研究者のAndrej Karpathy氏がX(旧Twitter)に投稿した言葉が起源です。「コードを書くのではなく、AIに意図(vibe)を伝えてコードを生成させる」という開発スタイルを指します。
具体的には次のような流れです。
- Cursor・GitHub Copilotなどのエディタ上でチャット欄に指示を入力する
- AIが数秒〜数十秒でコードを生成する
- 動作確認して問題なければそのまま使う
- 必要なら「エラーが出た、直して」と追加指示する
従来のプログラミングでは、開発者がコードの一行一行を理解して書いていました。バイブコーディングでは、コードの中身をほとんど読まずに開発が完了するケースがあります。これが速度面では革命的である一方、セキュリティ面では深刻な問題を生み出しています。
なぜバイブコーディングのコードはセキュリティリスクが高いのか
1. AIは「動作」を優先し、「セキュリティ」は後回しにする
AIモデルはユーザーの指示を実現することを最優先します。「ログイン機能を作って」と指示すれば、動くコードを返します。しかし「ブルートフォース攻撃への対策も入れて」「レートリミットを設けて」と明示しなければ、それらは省略されることがほとんどです。
セキュリティ要件をプロンプトに書かなければ、AIはそれを実装しません。AIは「あなたが意図していること」を推測するのは得意ですが、「あなたが忘れていること」を補完する義務は負っていません。
2. コードを読まないまま本番デプロイしがち
バイブコーディングの最大の問題の一つが、生成されたコードをレビューせずにデプロイすることです。コードを自分で書いていれば、少なくとも一度は全体を通して読みます。AIが書いたコードはそのままコピーして使われることが多く、潜在的な問題が見落とされます。
例として、ある開発者がCursorに「Firebase認証を使ったAPIを作って」と指示したところ、生成されたコードの中にテスト用のFirebase設定(APIキーを含む)がそのままハードコードされていたというケースがあります。本人はコードを読んでいなかったため、数ヶ月後にGitHubのパブリックリポジトリ経由で漏洩するまで気づきませんでした。
3. 依存パッケージの脆弱性を引き込みやすい
AIは指示された機能を実装するため、さまざまなnpmパッケージやPythonライブラリを使います。AIが選んだパッケージが最新版かどうか、既知の脆弱性を含んでいないかどうかは、開発者側で確認しない限りわかりません。
特に注意が必要なのは、AIが「一般的な実装例」として学習しているパターンが古い場合です。2024年以前のコード例を学習したモデルは、当時は安全だったが現在は脆弱性が発見されているパッケージを使う可能性があります。
4. 「動けばいい」で本番環境に上げてしまう
バイブコーディングでは、「プロトタイプのつもりで作ったもの」がそのまま本番運用されるケースが少なくありません。デバッグモードが有効なまま、テスト用の認証情報が残ったまま、エラーメッセージが詳細すぎるまま……という状態で外部公開されてしまいます。
バイブコーディングで特に起きやすい脆弱性パターン
パターン1: 認証・認可の欠如
最もよく見られる問題です。「APIを作って」「データを取得するエンドポイントを作って」という指示だけでは、認証なしのAPIが生成されることがあります。
危険なコード例(認証なしAPI):
# FastAPI で生成されたコードの例
from fastapi import FastAPI
import sqlite3
app = FastAPI()
@app.get("/users")
def get_all_users():
conn = sqlite3.connect("users.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
return cursor.fetchall()このコードは動きます。しかし、エンドポイントURLを知っている人なら誰でも全ユーザーデータを取得できます。
安全なコード例(JWT認証付き):
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
import sqlite3
app = FastAPI()
security = HTTPBearer()
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
try:
payload = jwt.decode(
credentials.credentials,
SECRET_KEY,
algorithms=["HS256"]
)
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/users")
def get_all_users(current_user: dict = Depends(verify_token)):
conn = sqlite3.connect("users.db")
cursor = conn.cursor()
cursor.execute("SELECT id, email, name FROM users") # パスワードを除外
return cursor.fetchall()パターン2: ハードコードされたシークレット
AIはサンプルコードとして認証情報をそのままコードに埋め込むことがあります。後から環境変数に移し替えることを「推奨」しても、実際にそれを行わずそのままGitにコミットされてしまうケースが頻発しています。
危険なコード例:
// AIが生成したNode.jsコード
const stripe = require('stripe')('sk_live_AbCdEfGhIjKlMnOpQrStUv123456');
const db = mysql.createConnection({
host: 'production-db.example.com',
user: 'admin',
password: 'SuperSecret123!',
database: 'myapp_prod'
});安全なコード例:
// 環境変数から読み込む
require('dotenv').config();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});.envファイルを作成し、.gitignoreに追加するところまでセットで実装する必要があります。
パターン3: SQLインジェクション
「SQLを直接書いて」と指示したり、ORMを使わないシンプルな実装を求めると、ユーザー入力を直接クエリに連結したコードが生成されることがあります。
危険なコード例:
# ユーザー入力を直接連結している
def search_products(keyword):
query = f"SELECT * FROM products WHERE name LIKE '%{keyword}%'"
cursor.execute(query)
return cursor.fetchall()このコードに keyword = "'; DROP TABLE products; --" を渡すと、テーブルが削除される可能性があります。
安全なコード例:
# プレースホルダーを使ったパラメータ化クエリ
def search_products(keyword):
query = "SELECT * FROM products WHERE name LIKE ?"
cursor.execute(query, (f"%{keyword}%",))
return cursor.fetchall()パターン4: CORS設定のワイルドカード
フロントエンドとバックエンドを分けた構成で、「CORSエラーが出た、解決して」と指示すると、最も手っ取り早い解決策として*(すべてのオリジンを許可)が設定されることがよくあります。
危険なコード例:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # すべてのオリジンを許可
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)安全なコード例:
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://yourapp.com",
"https://www.yourapp.com"
], # 許可するオリジンを明示
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Authorization", "Content-Type"],
)パターン5: デバッグモードのまま本番デプロイ
開発・テスト段階で有効にしたデバッグ設定が、本番環境でも残り続けることがあります。
危険なコード例(Djangoの設定ファイル):
# settings.py
DEBUG = True # 本番でTrueのまま
SECRET_KEY = 'django-insecure-abc123xyz' # デフォルトの弱いキー
ALLOWED_HOSTS = ['*'] # すべてのホストを許可DEBUG = Trueの状態では、エラーが発生したときにスタックトレース(ソースコードのパス、設定値、環境情報)がブラウザに表示されます。攻撃者に攻撃の糸口を提供することになります。
自分でできる最初のセキュリティチェック
完全な診断は専門家に依頼する必要がありますが、まず自分でできる初期チェックがあります。以下の手順で基本的な問題を発見できます。
チェック1: シークレットのスキャン(git-secrets / truffleHog)
リポジトリにAPIキーやパスワードが混入していないかを確認します。
# truffleHogのインストールと実行
pip install truffleHog3
# リポジトリ全体をスキャン
trufflehog filesystem ./ --json | jq '.SourceMetadata.Data.Filesystem.file'
# または git-secrets(AWSが提供)
brew install git-secrets
git secrets --scanGitHubのパブリックリポジトリにシークレットをプッシュしてしまった場合は、単純に削除しただけでは不十分です。Gitの履歴には残り続けるため、シークレットキーを必ず無効化・再発行してください。
チェック2: 依存パッケージの脆弱性チェック
# Node.js プロジェクトの場合
npm audit
# 自動修正を試みる場合
npm audit fix
# Python プロジェクトの場合
pip install pip-audit
pip-audit
# requirements.txtを指定する場合
pip-audit -r requirements.txtCRITICALやHIGHの重大度が表示された場合は、速やかな対応が必要です。
チェック3: 環境変数・設定ファイルのチェック
# .envファイルがGit管理に含まれていないか確認
git ls-files | grep -E '\.env$|\.env\.'
# .gitignoreに.envが含まれているか確認
cat .gitignore | grep env
# コード内のハードコードされた認証情報の簡易チェック
grep -rn "password\s*=\s*['\"]" . --include="*.py" --include="*.js"
grep -rn "secret\s*=\s*['\"]" . --include="*.py" --include="*.js"
grep -rn "api_key\s*=\s*['\"]" . --include="*.py" --include="*.js"チェック4: OWASP ZAPの基本スキャン
OWASP ZAP(Zed Attack Proxy)は無料で使えるWebアプリケーションセキュリティスキャナーです。
# Dockerを使ったOWASP ZAP自動スキャン
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py \
-t https://your-app-url.com \
-r zap_report.htmlスキャン結果のHIGHリスク項目については、特に優先して確認してください。
自己チェックリスト
チェック項目 | 確認方法 | 重要度 |
|---|---|---|
APIキー・パスワードがコードに直書きされていない | truffleHog / git-secrets | 緊急 |
.envファイルがGitにコミットされていない | git ls-files | 緊急 |
npm audit / pip-auditでCRITICAL・HIGHがない | 各コマンド実行 | 高 |
本番環境でDEBUGモードがオフになっている | 設定ファイル確認 | 高 |
APIエンドポイントに認証が設定されている | 動作確認 | 高 |
CORSがワイルドカード(*)になっていない | 設定ファイル確認 | 中 |
エラーメッセージに内部情報が含まれていない | ブラウザで確認 | 中 |
HTTPSが強制されている(HTTPにリダイレクト) | ブラウザで確認 | 中 |
専門家による脆弱性診断が必要なケース
自己チェックで問題がなくても、以下に該当するシステムは専門家による診断を強くお勧めします。
外部公開しているWebアプリケーション・API
インターネットから直接アクセスできるシステムは、常に攻撃の対象になっています。自動化された攻撃ツールは24時間365日、世界中のIPアドレスからスキャンを続けています。「小規模だから狙われない」という考えは誤りです。
個人情報・機密情報を扱うシステム
氏名・メールアドレス・住所・電話番号などの個人情報、契約情報、財務データなどを扱うシステムは、個人情報保護法の観点からも適切なセキュリティ対策が求められます。漏洩した場合の損害賠償・行政処分・レピュテーション損害を考えると、診断コストは非常に低い投資です。
決済機能を持つシステム
クレジットカード情報、銀行口座情報を扱うシステムはPCI DSSへの準拠が求められます。バイブコーディングで実装した決済フローは、セキュリティ要件が正しく実装されているか専門家に確認してもらう必要があります。
医療・法律・金融情報を扱うシステム
高度に機微な情報を扱うシステムは、業界固有のセキュリティ基準への対応も必要です。
リリースから時間が経過したシステム
最初は小さかったシステムが機能追加を重ねた場合、初期設計の問題がより大きなリスクに育っていることがあります。定期的な診断(年1回以上が推奨)が重要です。
脆弱性診断の費用目安
バイブコーディングで作られたシステムの診断費用は、システムの規模・複雑さ・診断の深さによって異なります。
診断種別 | 対象 | 費用の目安 |
|---|---|---|
ツール診断(自動スキャン中心) | 小〜中規模のWebアプリ | 30万〜80万円 |
マニュアル診断(専門家による手動) | 認証機能・API・決済フロー | 80万〜300万円 |
ソースコードレビュー | バイブコーディングで生成されたコード | 50万〜200万円 |
シークレットスキャン+設定レビュー | 軽微な初期チェック | 10万〜30万円 |
バイブコーディング案件では特にソースコードレビューを組み合わせることを推奨しています。ブラックボックス診断(外部からのスキャン)だけでは発見できない、コード内部のロジック欠陥やハードコードされたシークレットを洗い出せるためです。
Webアプリ脆弱性診断の費用相場の詳細については、Webアプリ脆弱性診断の費用相場と会社の選び方をご覧ください。
開発フローへのセキュリティ組み込み方
問題が発生してから対処するのではなく、バイブコーディングの段階からセキュリティを組み込む方法を紹介します。
AIへのプロンプトにセキュリティ要件を追加する
AIへの指示(プロンプト)にセキュリティ要件を明示することで、生成されるコードの安全性を高めることができます。以下のテンプレートを参考にしてください。
セキュリティ要件を含むプロンプトテンプレート:
【システムプロンプト(カスタム指示)に追加する内容】
コードを生成する際は以下のセキュリティ要件を必ず満たしてください:
1. 認証・認可
- すべてのAPIエンドポイントに適切な認証を実装する
- JWTを使う場合は有効期限を設定し、リフレッシュトークンを実装する
- ロールベースのアクセス制御(RBAC)を考慮する
2. シークレット管理
- APIキー・パスワード・トークンはコードに直書きしない
- 必ず環境変数(.env)から読み込む形で実装する
- .envファイルの.gitignore追加を必ず指示する
3. 入力バリデーション
- すべてのユーザー入力をバリデーションする
- SQLクエリはパラメータ化クエリまたはORMを使う
- ファイルアップロードは種類・サイズを制限する
4. エラーハンドリング
- エラーメッセージにスタックトレースや内部情報を含めない
- 本番環境ではデバッグモードをオフにする
5. 通信セキュリティ
- HTTPSを強制する
- セキュリティヘッダー(CSP、HSTS、X-Frame-Options等)を設定する
- CORSは必要なオリジンのみ許可するセキュリティレビューをワークフローに組み込む
フェーズ | 実施すること | ツール |
|---|---|---|
開発中(コミット前) | シークレットスキャン | git-secrets, truffleHog |
プッシュ前 | 依存パッケージ脆弱性チェック | npm audit, pip-audit |
デプロイ前 | 設定ファイルレビュー | チェックリスト |
外部公開前 | 自動スキャン | OWASP ZAP |
本番運用中(定期) | 専門家による診断 | ペネトレーションテスト |
CI/CDへの自動セキュリティチェック組み込み
GitHub Actionsを使った例です。
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog Scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
dependency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm audit --audit-level=highこのワークフローを設定することで、コードをプッシュするたびにシークレットスキャンと依存パッケージの脆弱性チェックが自動実行されます。
まとめ: バイブコーディングと付き合うためのセキュリティ原則
バイブコーディングはエンジニアリングの民主化という意味で革命的なツールです。しかし「AIが書いたから安全」という前提は危険です。
今日から実践できること(優先順位順):
- 緊急:
truffleHogでリポジトリにシークレットが含まれていないか確認する - 緊急:
npm audit/pip-auditで依存パッケージの脆弱性を確認する - 高: 本番環境のデバッグモードがオフになっているか確認する
- 高: 外部公開APIに認証が実装されているか確認する
- 中: プロンプトにセキュリティ要件を追加して、今後の開発に組み込む
そして、外部公開・個人情報取扱い・決済・医療情報などの重要システムについては、専門家による脆弱性診断を検討してください。
AIツールと専門家のセキュリティ診断を組み合わせることが、2026年以降のシステム開発における現実的なベストプラクティスです。
関連記事
AEVUSに相談する
バイブコーディングで作ったシステムのセキュリティ不安を感じている方は、AEVUSにご相談ください。
AEVUSでは、AIツールで生成されたコードの特性を踏まえたソースコードレビュー付き脆弱性診断を提供しています。「コードを読んでほしい」「外部公開前に診てほしい」「何から手をつければいいかわからない」という段階からご対応可能です。
まずはお気軽にお問い合わせください。現状のシステム構成をヒアリングしたうえで、最適な診断プランをご提案します。