mcpField
A
aif-security-checklist

aif-security-checklist

github.com/lee-toセキュリティ1.1k105 回インストール今日更新
リポジトリ

aif-security-checklist について

aif-security-checklistは、OWASP Top 10に基づいてアプリケーションとインフラのリスクを調べるセキュリティ監査スキルです。カテゴリ別監査、除外項目の記録、機械可読なゲート結果に対応します。

主な機能

  1. 01OWASP Top 10準拠の監査チェックリスト
  2. 02セキュリティカテゴリ別の確認
  3. 03自動監査スクリプト
  4. 04SECURITY.mdでの除外項目管理
  5. 05機械可読なゲート結果の追加

活用シーン

  1. 01認証とセッション処理の確認
  2. 02コードのインジェクションやXSSリスクの点検
  3. 03APIとインフラのセキュリティ評価
  4. 04後で見直す許容リスクの記録

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/lee-to/ai-factory --skill aif-security-checklist

インストール後、Claude Code で/aif-security-checklistを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
AUTH-PATTERNS.md
PROMPT-INJECTION.md
RACE-CONDITIONS.md
scripts/
audit.sh

詳細

セキュリティチェックリスト

OWASP Top 10(2021)と業界のベストプラクティスに基づく包括的なセキュリティチェックリストです。

クイックリファレンス

  • /aif-security-checklist — 完全な監査チェックリスト
  • /aif-security-checklist auth — 認証とセッション
  • /aif-security-checklist injection — SQL/NoSQL/コマンドインジェクション
  • /aif-security-checklist xss — クロスサイトスクリプティング
  • /aif-security-checklist csrf — クロスサイトリクエストフォージェリ
  • /aif-security-checklist secrets — シークレットと認証情報
  • /aif-security-checklist api — API セキュリティ
  • /aif-security-checklist infra — インフラストラクチャセキュリティ
  • /aif-security-checklist prompt-injection — LLM プロンプトインジェクション
  • /aif-security-checklist race-condition — 競合状態と TOCTOU
  • /aif-security-checklist ignore <item> — 特定のチェック項目を無視する

設定

最初に: .ai-factory/config.yaml が存在する場合は、以下を解決するために読み込みます。

  • パス: paths.security
  • 言語: プロンプト、監査サマリー、次のステップのガイダンスには language.ui、無視項目の状態を記録するアーティファクトには language.artifacts、無視項目のアーティファクト内で人が読む技術用語には language.technical_terms

config.yaml が存在しない場合は、既定値を使用します。

  • SECURITY.md:.ai-factory/SECURITY.md
  • ui_language:en
  • artifact_language:en
  • technical_terms_policy:keep

解決される言語の値:

  • ui_language = language.ui || "en"
  • artifact_language = language.artifacts || language.ui || "en"
  • technical_terms_policy = language.technical_terms || "keep"

technical_terms_policy が keep、translate、mixed のいずれでもない場合は、keep として扱います。english などの旧形式の値も keep と同様に扱います。

すべての AskUserQuestion プロンプト、監査サマリー、ユーザーに表示する無視項目の説明、次のステップのガイダンスは、必ず ui_language で記述してください。

paths.security にある永続的な SECURITY.md の無視項目アーティファクトは、必ず artifact_language で記述してください。

テンプレートと例は構成を定めるものであり、英語での出力を固定するものではありません。artifact_language が en 以外の場合は、人が読む見出し、表のキャプション、注記、生成時の無視理由、レビューガイダンスを翻訳してから保存してください。項目 ID、日付、作成者のハンドル名、コマンド、パス、設定キー、パッケージ名、API 名、セキュリティカテゴリ ID、重大度/ステータスの列挙値、未加工のエラー、および最終的な aif-gate-result JSON スキーマは変更しないでください。その他の人が読む用語には technical_terms_policy を適用してください。

無視項目(SECURITY.md)

監査を実行する前に、解決された SECURITY.md のパス(既定値:.ai-factory/SECURITY.md)を必ず読み込んでください。存在する場合、チームが無視すると決定したセキュリティチェックの一覧が記載されています。

無視の仕組み

ユーザーが /aif-security-checklist ignore <item> を実行した場合:

  1. 現在の解決済み SECURITY.md ファイルを読み込む(存在しない場合は作成する)
  2. この項目を無視する理由をユーザーに尋ねる
  3. 以下の形式に従って項目をファイルに追加する
  4. 項目が追加されたことを確認する

監査(/aif-security-checklist または特定のカテゴリ)を実行する場合:

  1. 最初に解決済み SECURITY.md ファイルを読み込む
  2. 現在の監査範囲に該当する無視項目ごとに、以下を行います。
    • 指摘事項として報告しない
    • 代わりに、末尾の独立したセクション「⏭️ Ignored Items」に表示する
    • チームが把握できるよう、各無視項目とその理由および日付を表示する
  3. 無視されていない項目は通常どおり監査する
SECURITY.md の形式

保存する前に、この構造を artifact_language で出力してください。以下の見出しは標準的な構造ラベルであり、英語の表記に固定されるものではありません。項目 ID と表の各フィールドの意味は変わりません。

# Security: Ignored Items

Items below are excluded from security-checklist audits.
Review periodically — ignored risks may become relevant.

| Item | Reason | Date | Author |
|------|--------|------|--------|
| no-csrf | SPA with token auth, no cookies used | 2025-03-15 | @dev |
| no-rate-limit | Internal microservice, behind API gateway | 2025-03-15 | @dev |

項目の命名規則 — 短い kebab-case の ID を使用してください。

  • no-csrf — CSRF トークンが実装されていない
  • no-rate-limit — レート制限が設定されていない
  • no-https — HTTPS が強制されていない
  • no-xss-csp — CSP ヘッダーがない
  • no-sql-injection — SQL インジェクションが完全に防止されていない
  • no-prompt-injection — LLM プロンプトインジェクションが緩和されていない
  • no-race-condition — 競合状態の防止策がない
  • no-secret-rotation — シークレットがローテーションされていない
  • no-auth-{route} — 特定のルートに認証がない
  • verbose-errors — 詳細なエラーが公開されている
  • または、任意の説明的なカスタム ID
無視した項目の出力例

監査結果を表示するときは、末尾にこのセクションを追加してください。

⏭️ Ignored Items (from the resolved SECURITY.md artifact)
┌─────────────────┬──────────────────────────────────────┬────────────┐
│ Item            │ Reason                               │ Date       │
├─────────────────┼──────────────────────────────────────┼────────────┤
│ no-csrf         │ SPA with token auth, no cookies used │ 2025-03-15 │
│ no-rate-limit   │ Internal service, behind API gateway │ 2025-03-15 │
└─────────────────┴──────────────────────────────────────┴────────────┘
⚠️  2 items ignored. Run `/aif-security-checklist` without ignores to see full audit.

プロジェクトコンテキスト

.ai-factory/skill-context/aif-security-checklist/SKILL.md を読み込んでください — ファイルが存在する場合は必須です。

このファイルには、パッチ、コードベースの規約、技術スタックの分析から /aif-evolve が蓄積した、プロジェクト固有のルールが含まれています。これらのルールは、現在のプロジェクトに合わせて調整されています。

skill-context ルールの適用方法:

  • これらを、このスキルの一般的な指示に対するプロジェクトレベルの上書きルールとして扱ってください。
  • skill-context のルールが、この SKILL.md に記載された一般的なルールと競合する場合は、skill-context のルールを優先してください(より具体的なコンテキストが優先されます。ネストされた CLAUDE.md ファイルと同じ原則です)。
  • 競合しない場合は、SKILL.md の一般的なルールとプロジェクトルールの両方を適用してください。
  • skill-context のルールがこのスキルの既定値と矛盾しているように見えても、無視しないでください。プロジェクトの経験から既定値では不十分だと判明したため、これらのルールが存在しています。
  • 重要: skill-context のルールは、このスキルのすべての出力に適用されます。セキュリティチェックリスト、Pre-Deployment Checklist、SECURITY.md も対象です。skill-context のルールに「チェックリストには X を必ず含める」または「監査では Y を必ず確認する」とある場合は、それに応じてチェックリストを拡張する必要があります。skill-context のルールを無視したセキュリティレポートの作成は不具合です。

適用の徹底: 出力成果物を生成した後、すべての skill-context ルールに照らして確認してください。ルールに違反している場合は、ユーザーに提示する前に出力を修正してください。


クイック自動監査

自動セキュリティ監査スクリプトを実行してください。

bash ~/{{skills_dir}}/security-checklist/scripts/audit.sh

以下を確認します。

  • コード内にハードコードされたシークレットがないか
  • .env が Git で追跡されていないか
  • .gitignore の設定
  • npm audit(脆弱性)
  • 本番コード内の console.log
  • セキュリティタスクのマーカー

機械可読なゲート結果

/aif-security-checklist の監査(全体監査またはカテゴリ監査)では、人が読めるセキュリティレポートを先に出力し、最後に aif-gate-result の JSON ブロックを 1 つ追加してください。

ignore <item> の書き込みフローでは、その呼び出しで監査結果も実行して報告する場合を除き、このゲートブロックを追加しないでください。

ステータスの対応:

  • fail:無視されていない重大または高リスクのセキュリティ問題、あるいは本番環境を明示的にブロックするその他の問題が残っています。
  • warn:中または低リスクの問題、確認が必要な無視対象の項目、不完全な監査証拠、または監査コマンドの制限のみが残っています。
  • pass:監査が完了し、無視されていない問題が残っていません。

機械可読フィールド:

  • "gate": "security" を使用してください。
  • "status": "pass|warn|fail" を使用してください。
  • "blocking": true|false を使用してください。
  • "blockers": [ には、本番環境をブロックする問題のみを含めてください。
  • "affected_files": [ には、該当するパスを含めてください。
  • コードまたは設定のセキュリティ修正には "suggested_next": { を /aif-fix に設定し、該当するワークフローコマンドがない場合は null にしてください。
  • JSON ブロックには、シークレット、トークン、平文パスワード、または非公開の認証情報を決して含めないでください。
{
  "schema_version": 1,
  "gate": "security",
  "status": "warn",
  "blocking": false,
  "blockers": [],
  "affected_files": ["src/api/session.ts"],
  "suggested_next": {
    "command": "/aif-fix",
    "reason": "Address non-blocking security hardening findings."
  }
}

🔴 重要:デプロイ前チェックリスト

本番環境への移行前に必ず修正
  • コードや Git の履歴にシークレットが含まれていない
  • すべてのユーザー入力を検証し、サニタイズしている
  • 保護対象のすべてのルートで認証を行っている
  • HTTPS を必須にしている(HTTP は使用しない)
  • SQL/NoSQL インジェクションを防止している
  • XSS 対策を実施している
  • 状態を変更するリクエストに CSRF トークンを設定している
  • レート制限を有効にしている
  • エラーメッセージから機密情報が漏えいしない
  • クライアント側のデバッグログは、本番環境では無効にするか、本番環境以外であることを明示的に確認した場合にのみ出力する
  • 本番環境の UI に、生のエラー、スタックトレース、例外メッセージ、SQL エラー、リクエストの内部情報、上流サービスの詳細を表示しない
  • 脆弱性がないか依存関係をスキャンしている
  • LLM のプロンプトインジェクションを軽減している(AI を使用する場合)
  • 重要な操作(決済、在庫など)で競合状態が発生しないようにしている

認証とセッション

パスワードのセキュリティ
✅ Requirements:
- [ ] Minimum 12 characters
- [ ] Hashed with bcrypt/argon2 (cost factor ≥ 12)
- [ ] Never stored in plain text
- [ ] Never logged
- [ ] Breach detection (HaveIBeenPwned API)

実装パターン(argon2、bcrypt、PHP、Laravel)については、references/AUTH-PATTERNS.md を参照してください。

セッション管理
✅ Checklist:
- [ ] Session ID regenerated after login
- [ ] Session timeout implemented (idle + absolute)
- [ ] Secure cookie flags set
- [ ] Session invalidation on logout
- [ ] Concurrent session limits (optional)

安全な Cookie 設定例については、references/AUTH-PATTERNS.md を参照してください。

JWT のセキュリティ
✅ Checklist:
- [ ] Use RS256 or ES256 (not HS256 for distributed systems)
- [ ] Short expiration (15 min access, 7 day refresh)
- [ ] Validate all claims (iss, aud, exp, iat)
- [ ] Store refresh tokens securely (httpOnly cookie)
- [ ] Implement token revocation
- [ ] Never store sensitive data in payload

インジェクション対策

SQL インジェクション
// ❌ VULNERABLE: String concatenation
const query = `SELECT * FROM users WHERE id = ${userId}`;

// ✅ SAFE: Parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);

// ✅ SAFE: ORM (Prisma/Eloquent/SQLAlchemy)
const user = await prisma.user.findUnique({ where: { id: userId } });
NoSQL インジェクション
// ❌ VULNERABLE: Direct user input — attack: { "$ne": "" }
const user = await db.users.findOne({ username: req.body.username });

// ✅ SAFE: Type validation
const username = z.string().parse(req.body.username);
コマンドインジェクション
// ❌ VULNERABLE: exec(`convert ${userFilename} output.png`);
// ✅ SAFE: execFile('convert', [userFilename, 'output.png']);

クロスサイトスクリプティング(XSS)

対策チェックリスト
- [ ] All user output HTML-encoded by default
- [ ] Content-Security-Policy header configured
- [ ] X-Content-Type-Options: nosniff
- [ ] Sanitize HTML if allowing rich text
- [ ] Validate URLs before rendering links
出力エンコーディング
// ❌ VULNERABLE: element.innerHTML = userInput; / dangerouslySetInnerHTML
// ✅ SAFE: element.textContent = userInput; / React: <div>{userInput}</div>
// ✅ If HTML needed: DOMPurify.sanitize(userInput)
// ❌ VULNERABLE: <?= $userInput ?> / {!! $userInput !!}
// ✅ SAFE: {{ $userInput }} (Blade) / htmlspecialchars($input, ENT_QUOTES, 'UTF-8')
コンテンツセキュリティポリシー

CSP ヘッダーを設定します:default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'


CSRF 対策

チェックリスト
- [ ] CSRF tokens on all state-changing requests
- [ ] SameSite=Strict or Lax on cookies
- [ ] Verify Origin/Referer headers
- [ ] Don't use GET for state changes
実装
  • サーバー側でレンダリングする場合:csurf ミドルウェアを使用し、トークンを非表示のフォームフィールドと AJAX ヘッダーに埋め込みます
  • SPA の場合:二重送信 Cookie パターンを使用します。sameSite: 'strict' を指定した読み取り可能な Cookie を設定し、クライアントがトークンをヘッダーで送信して、サーバーで照合します

シークレット管理

絶対にしてはいけないこと
❌ Secrets in code
const API_KEY = "sk_live_abc123";

❌ Secrets in git
.env committed to repository

❌ Secrets in logs
console.log(`Connecting with password: ${password}`);

❌ Secrets in error messages
throw new Error(`DB connection failed: ${connectionString}`);
チェックリスト
- [ ] Secrets in environment variables or vault
- [ ] .env in .gitignore
- [ ] Different secrets per environment
- [ ] Secrets rotated regularly
- [ ] Access to secrets audited
- [ ] No secrets in client-side code
Git 履歴のクリーンアップ
# If secrets were committed, remove from history
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch path/to/secret-file" \
  --prune-empty --tag-name-filter cat -- --all

# Or use BFG Repo-Cleaner (faster)
bfg --delete-files .env
bfg --replace-text passwords.txt

# Force push (coordinate with team!)
git push origin --force --all

# Rotate ALL exposed secrets immediately!

API セキュリティ

認証
- [ ] API keys not in URLs (use headers)
- [ ] Rate limiting per user/IP
- [ ] Request signing for sensitive operations
- [ ] OAuth 2.0 for third-party access
クライアント向けのログとエラー
- [ ] Browser/client logs are disabled in production or routed through a logger that no-ops debug output in production
- [ ] `console.log`, `console.debug`, `console.info`, and verbose client telemetry are gated by explicit non-production checks
- [ ] Production UI shows only client-safe error messages with minimal operational detail
- [ ] Raw exceptions, stack traces, SQL/ORM errors, validation library internals, upstream responses, file paths, env names, and secrets never reach UI text
- [ ] Full error details are logged server-side only, correlated with a request/error ID returned to the client
- [ ] Client-safe error payloads use stable codes/messages such as `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `CONFLICT`, or `INTERNAL_ERROR`
const isProduction = process.env.NODE_ENV === 'production';

// ✅ Client debug output is explicit and removed/no-op in production paths
if (!isProduction) {
  console.debug('Form validation state', formState);
}

// ✅ Normalize unknown errors before rendering them in UI
function toClientError(error: unknown) {
  if (isKnownClientError(error)) {
    return { code: error.code, message: error.publicMessage };
  }

  return {
    code: 'INTERNAL_ERROR',
    message: 'Something went wrong. Try again later.',
  };
}
入力検証
// ✅ Validate all input with schema
import { z } from 'zod';

const CreateUserSchema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100),
  age: z.number().int().min(0).max(150).optional(),
});

app.post('/users', (req, res) => {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({
      error: {
        code: 'VALIDATION_FAILED',
        message: 'Some fields are invalid.',
        fields: result.error.issues.map((issue) => ({
          path: issue.path.join('.'),
          code: issue.code,
        })),
      },
    });
  }
  // result.data is typed and validated
});
レスポンスのセキュリティ
// ✅ Don't expose internal errors
app.use((err, req, res, next) => {
  console.error(err); // Log full error internally

  // Return generic message to client
  res.status(500).json({
    error: {
      code: 'INTERNAL_ERROR',
      message: 'Something went wrong. Try again later.',
    },
    requestId: req.id, // For support reference
  });
});

// ✅ Don't expose sensitive fields
const userResponse = {
  id: user.id,
  name: user.name,
  email: user.email,
  // ❌ Never: password, passwordHash, internalId, etc.
};

インフラストラクチャのセキュリティ

ヘッダーのチェックリスト
app.use(helmet()); // Sets many security headers

// Or manually:
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '0'); // Disabled, use CSP instead
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
依存関係のセキュリティ
# Check for vulnerabilities
npm audit
pip-audit
cargo audit

# Auto-fix where possible
npm audit fix

# Keep dependencies updated
npx npm-check-updates -u
デプロイのチェックリスト
- [ ] HTTPS only (redirect HTTP)
- [ ] TLS 1.2+ only
- [ ] Security headers configured
- [ ] Debug mode disabled
- [ ] Default credentials changed
- [ ] Unnecessary ports closed
- [ ] File permissions restricted
- [ ] Logging enabled (but no secrets)
- [ ] Backups encrypted
- [ ] WAF/DDoS protection (for public APIs)

競合状態

競合状態の詳細なパターン(二重支払い、TOCTOU、楽観的ロック、冪等性キー、分散ロック)については、references/RACE-CONDITIONS.md を参照してください。

対策チェックリスト
- [ ] Financial operations use database transactions with proper isolation
- [ ] Inventory/stock checks use atomic decrement (not read-then-write)
- [ ] Idempotency keys on payment and mutation endpoints
- [ ] Optimistic locking (version column) on concurrent updates
- [ ] File operations use exclusive locks where needed
- [ ] No TOCTOU gaps between permission check and action
- [ ] Rate limiting to reduce exploitation window

プロンプトインジェクション(LLM セキュリティ)

プロンプトインジェクションの詳細なパターン(直接、間接、ツールの安全性、出力の検証、RAG)については、references/PROMPT-INJECTION.md を参照してください。

対策チェックリスト
- [ ] User input never concatenated directly into system prompts
- [ ] Input/output boundaries clearly separated (delimiters, roles)
- [ ] LLM output treated as untrusted (never executed as code/commands)
- [ ] Tool calls from LLM validated and sandboxed
- [ ] Sensitive data excluded from LLM context
- [ ] Rate limiting on LLM endpoints
- [ ] Output filtered for PII/secrets leakage
- [ ] Logging & monitoring for anomalous prompts

監査で使えるコマンド

# Find hardcoded secrets
grep -rn "password\|secret\|api_key\|token" --include="*.ts" --include="*.js" .

# Check for vulnerable dependencies
npm audit --audit-level=high

# Find unfinished security markers
grep -rn "[T][O][D][O].*security\|[F][I][X][M][E].*security\|[X][X][X].*security" .

# Check for console.log in production code
grep -rn "console\.log" src/

# Check for verbose browser logs that need a non-production guard
grep -rn "console\.\(log\|debug\|info\|trace\)" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" src/

# Check for raw error rendering patterns in UI/client code
grep -rn "\(error\.message\|err\.message\|String(error)\|String(err)\|stack\)" --include="*.tsx" --include="*.jsx" --include="*.ts" --include="*.js" src/

# Find prompt injection risks (unsanitized input in LLM calls)
grep -rn "system.*\${.*}" --include="*.ts" --include="*.js" .
grep -rn "innerHTML.*llm\|innerHTML.*response\|innerHTML.*completion" --include="*.ts" --include="*.js" .

重大度の目安

問題重大度修正期限
SQL インジェクション🔴 致命的直ちに
認証の回避🔴 致命的直ちに
シークレットの漏えい🔴 致命的直ちに
XSS(蓄積型)🔴 致命的24 時間以内
プロンプトインジェクション(直接)🔴 致命的直ちに
競合状態(金融)🔴 致命的直ちに
プロンプトインジェクション(間接)🟠 高1 週間以内
競合状態(データ)🟠 高1 週間以内
CSRF🟠 高1 週間以内
XSS(反射型)🟠 高1 週間以内
レート制限の未設定🟡 中2 週間以内
詳細すぎるエラー🟡 中2 週間以内
ヘッダーの未設定🟢 低1 か月以内

ヒント: セキュリティ監査後はコンテキストの使用量が多くなっています。他のタスクを続ける前に、/clear または /compact を実行することを検討してください。

アーティファクトの所有権と設定ポリシー

  • 主な所有権:ignore フローを通じて作成された無視項目の状態は、解決済みの SECURITY.md アーティファクト(デフォルト:.ai-factory/SECURITY.md)が管理します。
  • 書き込みポリシー:監査結果は通常、会話内で出力します。永続的な書き込みは、ユーザーが明示的に追加を依頼した場合を除き、上記の無視状態アーティファクトに限定されます。
  • 設定ポリシー:設定を考慮します。無視状態アーティファクトには paths.security を、プロンプトと監査の要約には language.ui を、無視項目アーティファクトには language.artifacts を、人が読める用語のポリシーには language.technical_terms を使用し、監査範囲はリポジトリの根拠と監査コマンドから導き出します。

コメント