AIコーディング 2026.05.13
AI生成コードの脆弱性チェック完全ガイド【Snyk・CVSS・GitHub Actions統合・2026年版】
AI生成コードが抱えやすい脆弱性パターン
ClaudeやChatGPTなどのAIは高速にコードを生成しますが、セキュリティより「動作する」ことを優先する傾向があります。特に多い脆弱性パターンは以下の4つです。
| 脆弱性タイプ | CVSS目安 | 典型的なAI生成の問題 |
|---|---|---|
| SQLインジェクション | 9.0〜9.8 | 入力値を直接SQLに埋め込む |
| ハードコードシークレット | 7.0〜9.0 | APIキー・パスワードをコードに直書き |
| コマンドインジェクション | 9.0〜10.0 | ユーザー入力をshellで実行 |
| 不十分な入力検証 | 5.0〜7.0 | バリデーションなしにデータを処理 |
脆弱なコードと安全なコードの対比
SQLインジェクション(CVSS 9.4相当)
# ❌ AI生成コードによくある危険なパターン
def get_user_by_name(username: str) -> dict:
conn = sqlite3.connect("users.db")
cursor = conn.cursor()
# ユーザー入力を直接SQLに埋め込んでいる
query = f"SELECT * FROM users WHERE username = '{username}'"
cursor.execute(query)
return cursor.fetchone()
# 攻撃例: username = "admin' OR '1'='1"
# → SELECT * FROM users WHERE username = 'admin' OR '1'='1'
# → 全ユーザーのデータが返る
# ✅ 安全な実装:プレースホルダーを使う
def get_user_by_name(username: str) -> dict | None:
conn = sqlite3.connect("users.db")
cursor = conn.cursor()
# パラメータ化クエリ(プレースホルダー)を使う
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
return cursor.fetchone()
ハードコードシークレット(CVSS 7.5相当)
# ❌ AIが生成しやすい危険なパターン
def send_notification(message: str):
client = anthropic.Anthropic(
api_key="sk-ant-api03-xxxxxxxxxxxx" # ← ハードコード禁止
)
# ...
DATABASE_URL = "postgresql://admin:password123@prod-db.example.com/users" # 危険
# ✅ 環境変数から取得する
import os
from anthropic import Anthropic
def send_notification(message: str):
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
raise ValueError("ANTHROPIC_API_KEY が設定されていません")
client = Anthropic(api_key=api_key)
# ...
DATABASE_URL = os.environ["DATABASE_URL"] # 環境変数から取得
コマンドインジェクション(CVSS 9.8相当)
# ❌ 危険:ユーザー入力を直接シェルに渡す
import subprocess
def ping_host(hostname: str) -> str:
result = subprocess.run(
f"ping -c 3 {hostname}",
shell=True, # shell=True は危険
capture_output=True,
text=True
)
return result.stdout
# 攻撃例: hostname = "example.com; rm -rf /var/log"
# ✅ 安全な実装:引数をリスト渡し・バリデーション付き
import subprocess
import re
def ping_host(hostname: str) -> str:
# ホスト名として有効な文字のみ許可
if not re.match(r'^[a-zA-Z0-9.-]+$', hostname):
raise ValueError(f"無効なホスト名: {hostname}")
result = subprocess.run(
["ping", "-c", "3", hostname], # shell=False(デフォルト)
capture_output=True,
text=True,
timeout=10
)
return result.stdout
Snykを使ったCI/CD統合
GitHub Actionsへの統合
# .github/workflows/security-scan.yml
name: セキュリティスキャン
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
snyk-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Snyk セキュリティスキャン(コード)
uses: snyk/actions/python@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high # High以上の脆弱性でCI失敗
- name: Snyk 依存関係スキャン
uses: snyk/actions/python@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: test
args: --file=requirements.txt --severity-threshold=high
Snyk CLIでローカルスキャン
# インストール
npm install -g snyk
# 認証
snyk auth
# Pythonプロジェクトをスキャン
snyk test --file=requirements.txt
# コードの静的解析(SAST)
snyk code test
# 脆弱性のレポートをJSONで出力
snyk test --json > snyk-report.json
AI生成コードをセキュアにするプロンプト設計
# セキュリティを意識したプロンプト例
Pythonで以下の仕様のAPIエンドポイントを実装してください:
[仕様]
- ユーザー検索API(GET /users?name=xxx)
- SQLiteデータベースを使用
[セキュリティ要件(必須)]
- SQLはパラメータ化クエリのみ使用(f-stringでSQL組み立て禁止)
- 入力値のバリデーション(長さ・文字種の制限)
- APIキー・パスワードは環境変数から取得
- エラー時にスタックトレースを返さない
- OWASP Top 10 を考慮した実装
[禁止事項]
- shell=True のsubprocess
- eval() や exec() の使用
- ハードコードされた認証情報
ローカルでのセキュリティチェックリスト
AI生成コードをレビューする際のチェック項目です:
# security_checklist.py
# AIが生成したコードをレビューする際の確認事項
CHECKLIST = {
"SQLインジェクション": [
"f-string や %s でSQL文を組み立てていないか",
"execute() の第2引数にタプルでパラメータを渡しているか",
],
"シークレット管理": [
"os.environ[] または os.getenv() で取得しているか",
".env ファイルが .gitignore に含まれているか",
"コード中にsk-、ghp_、Bearer などの文字列がないか",
],
"入力検証": [
"外部からの入力をそのまま使っていないか",
"型チェック・長さチェック・文字種チェックをしているか",
],
"コマンド実行": [
"shell=True を使っていないか",
"ユーザー入力をコマンドに渡す前にバリデーションしているか",
],
"エラーハンドリング": [
"例外のスタックトレースを外部に返していないか",
"詳細なエラー情報を本番環境でログに残しているか",
],
}
for category, items in CHECKLIST.items():
print(f"\n## {category}")
for item in items:
print(f" □ {item}")
あわせて読みたい
- AIコーディングエージェントのセキュリティリスク実例:開発チームを守る3つの脅威と対策
- 生成AIを業務で安全に使うための5つのルール
- Claude Code実行時の認証エラー「403 Forbidden」の原因と対処法