AI 生成コードのセキュリティ対策でいちばん効くのは、AI に「安全に書いて」と頼むことではありません。危ない変更を仕組みで止めることです。Veracode の 2026 年春の調査では、AI が書いたコードは 45% の課題で既知の脆弱性を含んでいました1。Georgia Tech の調査では、AI ツールが入れたと確認された CVE が 2026 年 1 月の 6 件から 3 月の 35 件に増えています23。この記事では、バイブコーディング(AI に任せてコードをほぼ読まずに作るやり方)で出やすい脆弱性の傾向を一次情報で整理します。そのうえで、Claude Code の permissions・hooks・/security-review と、CI に入れる gitleaks・semgrep を、筆者が実際に動かした設定つきで紹介します(内容は 2026 年 10 月時点)。
AI が書くコードは「動く」ようにはなりましたが、「安全」にはなっていません。Veracode は 2025 年から同じ 80 個の課題で 150 以上のモデルを測り続けています。その結果、文法として正しいコードの割合は 95% を超えた一方、セキュリティのテストに通る割合は約 55% のまま横ばいでした1。
失敗の中身には偏りがあります。SQL インジェクションや弱い暗号のように「見た目で分かる」ものは比較的避けられます。一方、入力がどこを通って出力されるかを追う必要があるクロスサイトスクリプティング(XSS)やログインジェクションは、ほとんど防げていません1。
AI 生成コードのセキュリティ合格率(脆弱性の種類別、Veracode 2026 年春)データを表で見る
AI 生成コードのセキュリティ合格率(脆弱性の種類別、Veracode 2026 年春)| 脆弱性の種類 | 合格率(%) |
|---|
| 弱い暗号(CWE-327) | 86 |
|---|
| SQL インジェクション(CWE-89) | 82 |
|---|
| XSS(CWE-80) | 15 |
|---|
| ログインジェクション(CWE-117) | 13 |
|---|
出典: Veracode「Spring 2026 GenAI Code Security Update」(2026-03-24)。80 課題・4 言語で 150 以上のモデルを評価
言語別では Python が 62%、C# が 58%、JavaScript が 57%、Java が 29% でした1。新しいモデルほど安全になる、という傾向もほぼ見られません。例外は推論を長く行う OpenAI のモデルで、70〜72% まで上がりました1。
実際に公開された脆弱性でも、同じことが起きています。Georgia Tech の Systems Software & Security Lab は「Vibe Security Radar」で、CVE の修正コミットから履歴をさかのぼり、脆弱なコードを入れたのが AI ツールかどうかを調べています3。
AI ツールが入れたと確認された CVE の数(月別、2026 年 1〜3 月)データを表で見る
AI ツールが入れたと確認された CVE の数(月別、2026 年 1〜3 月)| 月 | CVE の数(件) |
|---|
| 2026 年 1 月 | 6 |
|---|
| 2026 年 2 月 | 15 |
|---|
| 2026 年 3 月 | 35 |
|---|
出典: Georgia Tech Vibe Security Radar の集計を Cloud Security Alliance の research note(2026-04-04)が引用した値
2026 年 4 月の時点で確認された 74 件のうち、14 件が深刻度「Critical」、25 件が「High」でした3。中身はコマンドインジェクション、認証の回避、SSRF(サーバー側からのリクエスト偽造)などです3。研究者は、コミットに AI ツールの署名が残っているものしか数えられないため、実際は 5〜10 倍あると見ています2。
理由は 3 つあります。
- AI が書くコードの量が増えた: Cloud Security Alliance(CSA)が引用した Apiiro の調査では、AI を使う開発者は 3〜4 倍の速さでコミットし、セキュリティの指摘は 6 か月で月 1,000 件から 10,000 件超に増えました2
- 指針がそろった: OWASP は LLM アプリの Top 10(2025 年版)に続き、2025-12-09 に AI エージェント向けの Top 10(2026 年版)を公開しました45
- 開発ツール自体が狙われ始めた: Amazon Q の拡張機能に悪意あるプロンプトが混入した件(CVE-2025-8217)や、Cursor の MCP 設定を悪用する脆弱性が 2025 年に公開されています2
日本の技術記事でも関心は高まっています。Qiita で「Security」タグの付いた記事は、直近 14 日で 20 件と、その前の 14 日の 12 件から増えました。一方、Google トレンド(日本・過去 90 日、2026-10-05 取得)の相対値で、「バイブコーディング」は直近 4 週の平均が 6.2、その前の 8 週の平均が 7.3 で、伸びてはいません6。言葉の流行が落ち着き、実務で「どう守るか」に関心が移っている段階と言えます。
Qiita の「Security」タグ付き記事数(14 日間)データを表で見る
Qiita の「Security」タグ付き記事数(14 日間)| 期間 | 記事数(件) |
|---|
| 前の 14 日 | 12 |
|---|
| 直近 14 日 | 20 |
|---|
出典: 筆者集計(元データ: Qiita API v2、2026-10-05 取得)
一次情報から読み取れる傾向は、次の 5 つです。
| 傾向 | 具体例 | 出典 |
|---|
| データの流れを追う脆弱性に弱い | XSS の合格率 15%、ログインジェクション 13% | Veracode1 |
| 認証・認可が抜ける | 認証の回避、権限昇格の経路が 322% 増 | Georgia Tech3、CSA2 |
| シークレットを書き込む | Azure の認証情報の露出が AI 非利用者の約 2 倍 | CSA(Apiiro の調査)2 |
| 存在しないパッケージを使う | 約 20% のコードが実在しないパッケージを参照(スロップスクワッティングの温床) | CSA(USENIX Security 2025 の研究)2 |
| 開発ツールが乗っ取られる | ルールファイルに隠し文字で命令を仕込む、MCP 設定の書き換え | CSA2、OWASP5 |
スロップスクワッティングとは、AI がよく間違えて書くパッケージ名を攻撃者が先に登録し、マルウェアを入れさせる手口です2。
Georgia Tech の研究者は「エージェントが認証の無いものを作るのは、打ち間違いではなく最初から入った設計の欠陥だ」と述べています3。つまり、1 行ずつ眺めるレビューでは見つかりにくい種類の欠陥が増えています。
1 つの道具で全部は防げないので、書く前・書いている最中・コミット前・PR・CI の 5 か所に分けて止めます。
AI 生成コードを、権限設定・セッション内レビュー・コミット前の hooks・CI のスキャン・人のレビューの 5 つの層で順に止める構成図: 筆者作成(Claude Code 公式ドキュメントの多層防御の表をもとに作図)
| 層 | いつ | 道具 | 止めるもの |
|---|
| 1. 権限 | 書く前 | permissions の deny | .env などの読み取り、危険なコマンド |
| 2. セッション内 | 書いている最中 | security-guidance プラグイン、/security-review | インジェクションなどのよくある脆弱性 |
| 3. コミット前 | commit の直前 | hooks + gitleaks | シークレットの混入 |
| 4. CI | PR・push | gitleaks、semgrep | シークレット、言語別のルールで見つかる脆弱性 |
| 5. 人 | マージ前 | レビューのチェックリスト | 認可・設計の欠陥 |
Claude Code の公式ドキュメントも、プラグイン・/security-review・PR のレビュー・CI の静的解析を重ねる「多層防御」を勧めています7。以下、上から順に設定します。前提は Claude Code 2.1.289、macOS です。
まず、AI にシークレットを見せないようにします。Claude Code の permissions.deny に書いたファイルは、検索結果から外され、読み取りも編集もできなくなります8。
.claude/settings.json(リポジトリに入れてチームで共有)に次のように書きます。
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(git push --force *)",
"Bash(curl *)"
]
}
}
ルールは deny → ask → allow の順に評価され、deny に当たったものは allow で上書きできません8。
ただし、deny は完全な壁ではありません。公式ドキュメントにも次の注意があります8。
Bash(curl *) は、/usr/bin/curl や sh -c 'curl …' のような別の書き方は止めません
Read の deny は、grep -r のようにファイル名を書かずに読むコマンドや、Python などのスクリプトが自分で開くファイルには効きません
- OS のレベルで確実に止めたい場合は、サンドボックスを有効にします
次に、シークレットがコミットに入るのを止めます。Claude Code の hooks は、ツールを使う直前(PreToolUse)に自分のスクリプトを実行できます。スクリプトが終了コード 2 で終わると、Claude Code はその操作を止め、標準エラーの内容を Claude に返します9。
ここでは、Claude が git commit を実行する直前に、ステージ済みの変更を gitleaks(シークレット検出ツール)で調べます。.claude/hooks/block-secrets.sh を作ります。
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if ! echo "$COMMAND" | grep -qE '(^|[;&|[:space:]])git[[:space:]]+commit'; then
exit 0
fi
if ! command -v gitleaks >/dev/null 2>&1; then
echo "gitleaks が見つかりません。インストールしてから commit してください" >&2
exit 2
fi
cd "$CLAUDE_PROJECT_DIR" || exit 0
if ! REPORT=$(gitleaks git --staged --redact --no-banner -v . 2>&1); then
echo "Blocked: ステージ済みの変更にシークレットらしき文字列があります。" >&2
echo "$REPORT" | grep -E '^(RuleID|File|Line):' >&2
echo "値を環境変数か Secrets に移し、git rm --cached 等で外してから再度 commit してください。" >&2
exit 2
fi
exit 0
chmod +x .claude/hooks/block-secrets.sh で実行権限を付け、.claude/settings.json に hooks を足します。if に Bash(git commit *) を書くと、git commit のときだけスクリプトが起動します9。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git commit *)",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-secrets.sh"
}
]
}
]
}
}
動作を確かめるため、AI が書きがちな脆弱なコード(トークンの直書き、f 文字列の SQL、HTML の組み立て)を用意しました。トークンはランダムに作った偽物です。Claude Code が hooks に渡すのと同じ形の JSON をスクリプトに渡すと、commit が止まりました。続けて semgrep で同じファイルを調べると、7 件の指摘が出ます。
PreToolUse の hook が gitleaks で github-pat を見つけて終了コード 2 で commit を止め、続く semgrep が 7 件の脆弱性を報告する様子筆者の環境(macOS、gitleaks 8.30.1、semgrep 1.179.0)で実行した出力
使ったコードは次のとおりです(Flask。そのまま本番に出してはいけない例です)。
import sqlite3
from flask import Flask, request
app = Flask(__name__)
GITHUB_TOKEN = "ghp_..."
@app.route("/users")
def users():
name = request.args.get("name", "")
conn = sqlite3.connect("app.db")
rows = conn.execute(f"SELECT id, name FROM users WHERE name = '{name}'").fetchall()
return f"<h1>{name}</h1><p>{len(rows)} users</p>"
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0")
トークンを os.environ["GITHUB_TOKEN"] に、SQL をプレースホルダ(?)に、HTML を render_template に、app.run() を引数なしに直すと、hook は通り、semgrep の指摘は 0 件になりました。
hooks の基本は「Claude Code の hooks 入門」で詳しく扱っています。
コードを書き終えたら、Claude Code の /security-review を実行します。今のブランチと origin のデフォルトブランチとの差分を読み、インジェクション、認証の問題、データの露出などを探します7。origin のリモートが必要です7。
/security-review
毎回打つのが面倒なら、Anthropic 公式の security-guidance プラグインを入れます。入れると、Claude がファイルを編集するたび・ターンが終わるたび・commit や push のたびに、自動で見直しが走ります7。
/plugin install security-guidance@claude-plugins-official
このプラグインの特徴は次のとおりです7。
- 編集のたびに、
eval( や .innerHTML =、pickle などの危険なパターンを文字列で照合する(モデルは呼ばない)
- ターンの終わりに、変更の差分を別の Claude(新しいコンテキスト)が見直す。書いた本人に採点させない
- どの層も書き込みや commit を止めない。見つけた問題は Claude に修正の指示として返る
止める役は手順 2 の hooks、見つけて直す役はプラグイン、と分けると考えやすくなります。リポジトリ全体を深く調べたいときは、別の Claude Security プラグイン(/claude-security)もあります7。
手元の対策は、設定していない人や別のツールで書いたコードには効きません。最後の砦として CI で止めます。.github/workflows/security.yml を作ります。
name: security
on:
pull_request: {}
push:
branches: ["main"]
permissions:
contents: read
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- uses: actions/checkout@v6
- run: semgrep scan --config p/default --error --metrics=off
gitleaks のジョブは gitleaks-action の README の例10、semgrep のジョブは Semgrep 公式の Community Edition 向けの例10をもとにしています。筆者は actionlint 1.7.12 で文法を確かめ、手元で semgrep scan --config p/default --error を実行して、脆弱なコードでは終了コード 1(10 件の指摘)になることを確かめました。GitHub 上での実行は試していません。
設定のポイントは 3 つです。
fetch-depth: 0: gitleaks が履歴全体を調べられるように、全コミットを取得します10
GITLEAKS_LICENSE: Organization のリポジトリでは gitleaks.io で無料のライセンスキーを取得して Secrets に入れます。個人アカウントのリポジトリでは要りません10
--error: semgrep は指摘があっても既定では成功(終了コード 0)で終わります(筆者の環境で確認)。--error を付けると指摘があったときに失敗します
ブランチ保護でこの 2 つのジョブを必須にすれば、指摘が残ったままではマージできなくなります。AI に PR をレビューさせる方法は「Claude Code を GitHub Actions で動かして PR レビューを自動化」で扱っています。
ツールが見つけにくい認可や設計の欠陥は、人が見ます。OWASP の Top 1045 と、上の調査で多かった欠陥をもとに、AI が書いた PR を見るときの観点をまとめました。
| 観点 | 確かめること |
|---|
| 認証・認可 | 新しいエンドポイントに認証があるか。他人の ID を渡したときに他人のデータが返らないか |
| 入力の流れ | ユーザー入力が SQL・HTML・ログ・シェルに届くまでに、エスケープやプレースホルダを通るか |
| シークレット | キーやトークンが直書きされていないか。ログやエラーメッセージに出ていないか |
| 依存パッケージ | 追加されたパッケージが実在し、名前の綴りが正しく、ダウンロード数や保守状況に問題がないか |
| 設定 | デバッグモード、0.0.0.0 での待ち受け、CORS の *、緩い権限が本番に残っていないか |
| エージェントの権限 | 追加された MCP サーバーや hooks、CI のトークンの権限が必要最小限か |
| テスト | 正常系だけでなく、権限の無いユーザー・不正な入力のテストがあるか |
チェックリストは CLAUDE.md に書いておくと、Claude Code が最初から意識してコードを書きます。書き方は「CLAUDE.md の書き方」を参照してください。
- deny を書いたのに読まれた: deny のルールは Claude が書くコマンドの文字列に当てはめるもので、別の書き方やスクリプト経由のアクセスは止めません8。確実に止めるにはサンドボックスを使います
- hook が動かない:
chmod +x を忘れていないか、jq と gitleaks が PATH にあるかを確かめます。hook は Claude Code が実行する commit にしか効かないので、自分のシェルからの commit には pre-commit などで別に入れます
- hook で終了コード 1 を返した: 止めたいときは終了コード 2 を返します。それ以外の終了コードは、多くの場合「エラーだが処理は続く」扱いになります9
/security-review が ambiguous argument で失敗する: origin のリモートとデフォルトブランチの情報が必要です7
- semgrep の誤検知が多い: 最初はルールセットを言語別(例:
p/python)に絞り、本当に問題のない行だけ # nosemgrep で除外します。除外の理由は PR に書いておきます
- AI のレビューを信じすぎる: security-guidance プラグインも、見落とすことがあると公式に書かれています7。AI のレビューは層の 1 つとして扱います
- AI 生成コードは約 45% の課題で既知の脆弱性を含み、モデルが新しくなってもほぼ改善していません1
- 特に XSS・ログインジェクション・認証の抜け・シークレットの直書き・存在しないパッケージに注意します
- 対策は、permissions の deny → セッション内のレビュー → hooks で commit 前に gitleaks → CI の gitleaks・semgrep → 人のチェックリスト、の 5 層で重ねます
- deny も hooks も AI のレビューも単独では完全ではないので、CI で必ず止まる層を 1 つ持ちます
- 次にやること: まず手順 1 の deny と手順 4 の CI を入れ、既存のリポジトリに
gitleaks git を 1 回かけて、過去のコミットにシークレットが無いか確かめましょう
一概には言えませんが、量が増える分だけ危険も増えます。Veracode の調査では AI が書いたコードの約 45% が既知の脆弱性を含んでいました1。CSA が引用した企業の調査では、AI を使う開発者はコミットが 3〜4 倍に増え、セキュリティの指摘は 10 倍に増えました2。
十分ではありません。Veracode の測定は、セキュリティの指示を出さない状態での結果です1。指示で改善する余地はありますが、確実ではないので、hooks や CI のように指示に頼らない仕組みと組み合わせます。
/security-review は、自分で実行したときに今のブランチの差分を 1 回見直します。security-guidance プラグインは、編集・ターンの終わり・commit のたびに自動で見直します7。日常はプラグイン、PR を出す前に /security-review、と使い分けられます。
どちらも手元のコマンドとしては無料で使えます。GitHub Actions の gitleaks-action は、Organization のリポジトリでは無料のライセンスキーの登録が必要です10。semgrep の Community Edition は semgrep scan で使え、AppSec Platform を使う場合は SEMGREP_APP_TOKEN が要ります10。
まずそのキーを無効にして新しいキーを発行します。履歴から消しても、すでに push していれば第三者に取得された可能性があるからです。そのあと履歴の書き換えや、今後の混入を防ぐ hooks・CI を入れます。
-
Spring 2026 GenAI Code Security Update: Despite Claims, AI Models Are Still Failing Security — Veracode, 2026-03-24(2026-10-05 参照) ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Vibe Coding's Security Debt: The AI-Generated CVE Surge — Cloud Security Alliance AI Safety Initiative, 2026-04-04(2026-10-05 参照) ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Bad Vibes: AI-Generated Code is Vulnerable, Researchers Warn — Georgia Tech Research News, 2026-04-13(2026-10-05 参照) ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
OWASP Top 10 for LLM Applications 2025 — OWASP GenAI Security Project(2026-10-05 参照) ↩ ↩2
-
OWASP Top 10 for Agentic Applications for 2026 — OWASP GenAI Security Project, 2025-12-09(2026-10-05 参照) ↩ ↩2 ↩3
-
Google トレンド「バイブコーディング」(日本・過去 90 日) — Google, 2026-10-05 取得。直近 4 週の平均 6.2、前 8 週の平均 7.3(相対値) ↩
-
Catch security issues as Claude writes code と Commands — Claude Code Docs, Anthropic(2026-10-05 参照) ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Configure permissions と All settings: permissions.deny — Claude Code Docs, Anthropic(2026-10-05 参照) ↩ ↩2 ↩3 ↩4
-
Automate actions with hooks — Claude Code Docs, Anthropic(2026-10-05 参照) ↩ ↩2 ↩3
-
gitleaks/gitleaks-action README — Gitleaks、および Sample CI configurations — Semgrep Docs(いずれも 2026-10-05 参照) ↩ ↩2 ↩3 ↩4 ↩5 ↩6