mcpField
S
security-review

security-review

github.com/factory-aiセキュリティ119159 回インストール5 日前に更新
リポジトリ

security-review について

STRIDEの脅威モデリングを用いて、コードと依存関係を調べるリポジトリ向けセキュリティレビュー用スキルです。悪用可能性を検証し、PR、定期スキャン、全リポジトリ監査の結果を出力します。

主な機能

  1. 01STRIDEカテゴリ別の脆弱性スキャン
  2. 02既知のCVEに関する依存関係チェック
  3. 03到達可能性と悪用可能性の評価
  4. 04低信頼度の検出結果と誤検知の除外
  5. 05モードに応じたPRコメントやレポートの作成

活用シーン

  1. 01マージ前のPR変更レビュー
  2. 02直近7日間のコミットスキャン
  3. 03リポジトリ全体のセキュリティ監査

インストール

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

$npx skills add https://github.com/factory-ai/factory-plugins --skill security-review

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

詳細

セキュリティレビュー

LLM を活用した推論と STRIDE 脅威モデリングを用いて、対象を絞ったセキュリティレビューを実施するシニアセキュリティエンジニアです。このスキルはコードをスキャンして脆弱性を検出し、発見事項の悪用可能性を検証します。

このスキルを使用するタイミング

  • PR のセキュリティレビュー - マージ前にコード変更を分析します
  • 毎週の定期スキャン - 過去 7 日間のコミットをレビューします
  • リポジトリ全体の監査 - 包括的なセキュリティ評価を実施します
  • 手動での実行 - PR コメントで @droid security を使用します

前提条件

  • レビュー対象のコードを含む Git リポジトリ
  • .factory/threat-model.md(存在しない場合は threat-model-generation スキルで自動生成されます)

ワークフロー内の位置

┌──────────────────────┐
│ threat-model-        │  ← Generates STRIDE threat model
│ generation           │
└─────────┬────────────┘
          ↓ .factory/threat-model.md
┌──────────────────────┐
│ security-review      │  ← THIS SKILL (scan + validate)
│ (commit-scan +       │
│  validation)         │
└─────────┬────────────┘
          ↓ validated-findings.json
┌──────────────────────┐
│ security-patch-      │  ← Generates fixes
│ generation           │
└──────────────────────┘

入力

入力説明必須デフォルト
モードpr、weekly、full、staged、commit-rangeいいえpr(自動検出)
ベースブランチ差分比較の対象ブランチいいえPR から自動検出
CVE の確認期間依存関係の CVE をさかのぼって確認する期間いいえ12 か月
重大度のしきい値報告する最小重大度いいえmedium

手順

ステップ 1:脅威モデルを確認する
# Check if threat model exists
if [ -f ".factory/threat-model.md" ]; then
  echo "Threat model found"
  # Check age
  LAST_MODIFIED=$(stat -f %m .factory/threat-model.md 2>/dev/null || stat -c %Y .factory/threat-model.md)
  DAYS_OLD=$(( ($(date +%s) - $LAST_MODIFIED) / 86400 ))
  if [ $DAYS_OLD -gt 90 ]; then
    echo "WARNING: Threat model is $DAYS_OLD days old. Consider regenerating."
  fi
else
  echo "No threat model found. Generate one first using threat-model-generation skill."
fi

存在しない場合:

  • PR モード:脅威モデルを自動生成して PR ブランチにコミットしてから、続行します
  • 週次/全体モード:脅威モデルを自動生成してレポート用 PR に含めてから、続行します

古くなっている場合(90 日超):

  • PR モード:コメントで警告し、既存のものを使用して続行します
  • 週次/全体モード:スキャン前に自動再生成します
ステップ 2:スキャン範囲を決定する
# PR mode - scan PR diff
git diff --name-only origin/HEAD...
git diff --merge-base origin/HEAD

# Weekly mode - last 7 days on default branch
git log --since="7 days ago" --name-only --pretty=format: | sort -u

# Full mode - entire repository
find . -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" -o -name "*.java" \) | head -500

# Staged mode - staged changes only
git diff --staged --name-only

以下を記録します:

  • 分析対象のファイル
  • コミット範囲(該当する場合)
  • 脅威モデルに基づくデプロイコンテキスト
ステップ 3:セキュリティスキャン(STRIDE ベース)

脅威モデルを読み込み、各 STRIDE カテゴリの脆弱性についてコードをスキャンします:

S - なりすまし

次を確認します:

  • 脆弱な認証メカニズム
  • セッショントークンの脆弱性(localStorage への保存、httpOnly の欠如)
  • API キーの露出
  • JWT の脆弱性(none アルゴリズム、弱いシークレット)
  • 機密性の高い操作における MFA の欠如
T - データの改ざん

次を確認します:

  • SQL インジェクション - クエリ内での文字列補間
  • コマンドインジェクション - システムコールに渡されるユーザー入力
  • XSS - エスケープされていない出力、innerHTML、dangerouslySetInnerHTML
  • マスアサインメント - 検証されていないオブジェクトの更新
  • パストラバーサル - ファイルパスに使用されるユーザー入力
  • XXE - XML の外部エンティティ処理
R - 否認

次を確認します:

  • 機密性の高い操作に対する監査ログの欠如
  • 管理者操作のロギング不足
  • 不変の監査証跡がない
I - 情報漏えい

次を確認します:

  • IDOR - 認可なしでのオブジェクトへの直接アクセス
  • 詳細すぎるエラー - レスポンスに含まれるスタックトレースやデータベースの詳細
  • ハードコードされたシークレット - コード内の API キーやパスワード
  • データ漏えい - ログ内の PII、デバッグ情報の露出
D - サービス拒否

次を確認します:

  • レート制限の欠如
  • 上限のないファイルアップロード
  • 正規表現 DoS(ReDoS)
  • リソースの枯渇
E - 権限昇格

次を確認します:

  • 認可チェックの欠如
  • マスアサインメントによるロール/権限の操作
  • 権限昇格につながる経路
  • RBAC の回避
検出するコードパターン
# SQL Injection (Tampering)
sql = f"SELECT * FROM users WHERE id = {user_id}"  # VULNERABLE
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))  # SAFE

# Command Injection (Tampering)
os.system(f"ping {user_input}")  # VULNERABLE
subprocess.run(["ping", "-c", "1", user_input])  # SAFE

# XSS (Tampering)
element.innerHTML = userInput;  // VULNERABLE
element.textContent = userInput;  // SAFE

# IDOR (Information Disclosure)
def get_doc(doc_id):
    return Doc.query.get(doc_id)  # VULNERABLE - no ownership check

# Path Traversal (Tampering)
file_path = f"/uploads/{user_filename}"  # VULNERABLE
filename = os.path.basename(user_input)  # SAFE
ステップ 4:依存関係の脆弱性スキャン

既知の CVE について依存関係をスキャンします:

# Node.js
npm audit --json 2>/dev/null

# Python
pip-audit --format json 2>/dev/null

# Go
govulncheck -json ./... 2>/dev/null

# Rust
cargo audit --json 2>/dev/null

脆弱性ごとに、次を実施します:

  1. 該当バージョンが影響を受けることを確認します
  2. 脆弱な API の使用箇所をコードベース内で検索します
  3. 到達可能性を REACHABLE、POTENTIALLY_REACHABLE、NOT_REACHABLE に分類します
ステップ 5:初期の発見事項を生成する

security-findings.json を出力します:

{
  "scan_id": "scan-<timestamp>",
  "scan_date": "<ISO timestamp>",
  "scan_mode": "pr | weekly | full",
  "commit_range": "abc123..def456",
  "threat_model_version": "1.0.0",
  "findings": [
    {
      "id": "VULN-001",
      "severity": "HIGH",
      "stride_category": "Tampering",
      "vulnerability_type": "SQL Injection",
      "cwe": "CWE-89",
      "file": "src/api/users.js",
      "line_range": "45-49",
      "code_context": "const sql = `SELECT * FROM users WHERE name LIKE '%${query}%'`",
      "analysis": "User input from query parameter directly interpolated into SQL query without parameterization.",
      "exploit_scenario": "Attacker submits: test' OR '1'='1 to bypass search filter and retrieve all users.",
      "threat_model_reference": "Section 5.2 - SQL Injection",
      "recommended_fix": "Use parameterized queries: db.query('SELECT * FROM users WHERE name LIKE $1', [`%${query}%`])",
      "confidence": "HIGH"
    }
  ],
  "dependency_findings": [
    {
      "id": "DEP-001",
      "package": "lodash",
      "version": "4.17.20",
      "ecosystem": "npm",
      "vulnerability_id": "CVE-2021-23337",
      "severity": "HIGH",
      "cvss": 7.2,
      "fixed_version": "4.17.21",
      "reachability": "REACHABLE",
      "reachability_evidence": "lodash.template() called in src/utils/email.js:15"
    }
  ],
  "summary": {
    "total_findings": 5,
    "by_severity": {"CRITICAL": 0, "HIGH": 2, "MEDIUM": 2, "LOW": 1},
    "by_stride": {
      "Spoofing": 0,
      "Tampering": 2,
      "Repudiation": 0,
      "InfoDisclosure": 2,
      "DoS": 0,
      "ElevationOfPrivilege": 1
    }
  }
}
ステップ 6:発見事項を検証する

発見事項ごとに、悪用可能性を評価します:

  1. 到達可能性の分析 - 脆弱なコードパスは外部入力から到達可能ですか?
  2. 制御フローの追跡 - 攻撃者は脆弱性に到達する入力を制御できますか?
  3. 緩和策の評価 - 既存の対策(検証、サニタイズ、WAF)はありますか?
  4. 悪用可能性の確認 - 悪用はどの程度困難ですか?
  5. 影響の分析 - 脅威モデルに基づく影響範囲はどの程度ですか?
誤検知の除外

厳格な除外項目 — 自動的に除外します:

  1. 重大なビジネス影響を伴わないサービス拒否(DoS)
  2. 適切に保護されたディスク上のシークレット
  3. レート制限に関する懸念(情報提供のみ)
  4. 明確な攻撃経路を伴わないメモリ/CPUの枯渇
  5. 実証された影響を伴わない入力検証の欠如
  6. 信頼できない特定の入力経路を伴わないGitHub Actionの脆弱性
  7. 実用的な悪用方法のない理論上の競合状態
  8. メモリ安全な言語(Rust、Go)におけるメモリ安全性の問題
  9. テストファイルのみで見つかった問題
  10. ログへのインジェクション/なりすましに関する懸念
  11. パスのみを制御するSSRF(ホスト/プロトコルは制御しない)
  12. AIプロンプト内のユーザー制御コンテンツ
  13. 影響が実証されていないReDoS
  14. ドキュメントファイルで見つかった問題
  15. 監査ログの欠如(情報提供のみ)

前例:

  • 環境変数とCLIフラグは信頼できるものとして扱います
  • UUIDは推測できません
  • dangerouslySetInnerHTMLまたはbypassSecurityTrustHtmlを使用しない限り、React/AngularはXSSに対して安全です
  • クライアント側コードで認証チェックを行う必要はありません(サーバー側の責任です)
  • ほとんどのipythonノートブックに関する指摘は悪用できません
確信度のスコアリング
  • 0.9-1.0:確実な悪用経路があり、動作するPoCを作成できます
  • 0.8-0.9:既知の悪用方法がある、明確な脆弱性のパターンです
  • 0.7-0.8:特定の条件を必要とする疑わしいパターンです
  • 0.7未満:報告しません(推測に頼りすぎています)

確信度が0.8以上の指摘のみ報告してください

ステップ7:概念実証を作成

確認済みのHIGH/CRITICALの指摘について、最小限のPoCを作成します:

{
  "proof_of_concept": {
    "payload": "' OR '1'='1",
    "request": "GET /api/users?search=test%27%20OR%20%271%27%3D%271",
    "expected_behavior": "Returns users matching 'test'",
    "actual_behavior": "Returns ALL users due to SQL injection"
  }
}
ステップ8:検証済みの指摘を生成

validated-findings.jsonを出力します:

{
  "validation_id": "val-<timestamp>",
  "validation_date": "<ISO timestamp>",
  "scan_id": "scan-<timestamp>",
  "threat_model_path": ".factory/threat-model.md",
  "validated_findings": [
    {
      "id": "VULN-001",
      "original_severity": "HIGH",
      "validated_severity": "HIGH",
      "status": "CONFIRMED",
      "stride_category": "Tampering",
      "vulnerability_type": "SQL Injection",
      "cwe": "CWE-89",
      "exploitability": "EASY",
      "reachability": "EXTERNAL",
      "file": "src/api/users.js",
      "line": 45,
      "existing_mitigations": [],
      "exploitation_path": [
        "User submits search query via GET /api/users?search=<payload>",
        "Express parses query string without validation",
        "Query passed directly to SQL template literal",
        "Database executes malicious SQL"
      ],
      "proof_of_concept": {
        "payload": "' OR '1'='1",
        "request": "GET /api/users?search=test%27%20OR%20%271%27%3D%271",
        "expected_behavior": "Returns users matching search",
        "actual_behavior": "Returns all users"
      },
      "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "cvss_score": 9.1,
      "recommendation": "Use parameterized queries",
      "references": [
        "https://cwe.mitre.org/data/definitions/89.html",
        "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"
      ]
    }
  ],
  "false_positives": [
    {
      "id": "VULN-003",
      "reason": "Input validated by Joi schema in middleware before reaching this endpoint",
      "evidence": "Validation in src/middleware/validate.js:12"
    }
  ],
  "dependency_findings": [
    {
      "id": "DEP-001",
      "status": "CONFIRMED",
      "package": "lodash",
      "version": "4.17.20",
      "vulnerability_id": "CVE-2021-23337",
      "severity": "HIGH",
      "reachability": "REACHABLE",
      "reachability_evidence": "lodash.template() called in src/utils/email.js:15",
      "fixed_version": "4.17.21"
    }
  ],
  "summary": {
    "total_scanned": 8,
    "confirmed": 5,
    "false_positives": 3,
    "by_severity": {
      "critical": 1,
      "high": 2,
      "medium": 1,
      "low": 1
    },
    "by_stride": {
      "Spoofing": 0,
      "Tampering": 3,
      "Repudiation": 0,
      "InfoDisclosure": 1,
      "DoS": 0,
      "ElevationOfPrivilege": 1
    }
  }
}
ステップ9:結果を出力(モードに依存)
PRモード:インラインコメント

指摘ごとに、インラインPRコメントを投稿します:

🔴 **CRITICAL: SQL Injection (CWE-89)**

**STRIDE Category:** Tampering
**Confidence:** High
**File:** `src/api/users.js:45-49`

**Analysis:**
User input from `req.query.search` is directly interpolated into SQL query without parameterization.

**Suggested Fix:**
```diff
- const query = `SELECT * FROM users WHERE name LIKE '%${search}%'`;
- const results = await db.query(query);
+ const query = `SELECT * FROM users WHERE name LIKE $1`;
+ const results = await db.query(query, [`%${search}%`]);

CWE-89: SQL Injection


Post summary tracking comment:

```markdown
## 🔒 Security Review Summary

| Severity | Count |
|----------|-------|
| 🔴 Critical | 1 |
| 🟠 High | 2 |
| 🟡 Medium | 3 |
| 🔵 Low | 0 |

### Findings
| ID | Severity | Type | File | Status |
|----|----------|------|------|--------|
| VULN-001 | Critical | SQL Injection | src/api/users.js:45 | Action required |
| VULN-002 | High | XSS | src/components/Comment.tsx:23 | Suggested fix |

---
*Reply `@droid dismiss VULN-XXX reason: <explanation>` to acknowledge a finding.*
週次/全件モード:セキュリティレポートPR

ブランチを作成します:droid/security-report-{YYYY-MM-DD}

PRタイトル:fix(security): Security scan report - {date} ({N} findings)

以下を含めます:

  • .factory/security/reports/security-report-{YYYY-MM-DD}.md
  • validated-findings.json
  • 更新済みの.factory/threat-model.md(再生成した場合)
ステップ10:重大度に応じた対応
重大度PRモード週次/全件モード
CRITICALREQUEST_CHANGES — マージをブロック優先度HIGHの課題を作成し、セキュリティチームに通知
HIGHREQUEST_CHANGES(設定可能)課題を作成し、レビューを必須とする
MEDIUMCOMMENTのみ課題を作成
LOWCOMMENTのみレポートに含める

重大度の定義

重大度基準例
CRITICALただちに悪用可能で影響が大きく、認証が不要RCE、本番環境のシークレットのハードコード、認証のバイパス
HIGHいくつかの条件下で悪用可能で、影響が大きいSQLインジェクション、保存型XSS、IDOR
MEDIUM特定の条件を必要とし、影響は中程度反射型XSS、CSRF、情報漏えい
LOW悪用が困難で、影響が小さい詳細すぎるエラー、セキュリティヘッダーの欠如

脆弱性の対象範囲

STRIDEカテゴリ脆弱性の種類
なりすまし脆弱な認証、セッションハイジャック、トークンの露出、認証情報の詰め込み攻撃
改ざんSQLインジェクション、XSS、コマンドインジェクション、マスアサインメント、パストラバーサル
否認監査ログの欠如、不十分なログ記録
情報漏えいIDOR、詳細すぎるエラー、シークレットのハードコード、データ漏えい
DoSレート制限の欠如、リソース枯渇、ReDoS
権限昇格認可の欠如、ロールの操作、RBACのバイパス

成功基準

  • 脅威モデルを確認/生成した
  • 変更されたすべてのファイルをスキャンした
  • 依存関係をCVEについてスキャンした
  • 指摘の悪用可能性を検証した
  • 誤検知を除外した
  • validated-findings.jsonを生成した
  • 適切な形式(PRコメントまたはレポート)で結果を出力した
  • 重大度に応じた対応を適用した

使用例

PR のセキュリティレビュー:

Scan PR #123 for security vulnerabilities.

PR での手動トリガー:

@droid security

リポジトリ全体のスキャン:

@droid security --full

週次スキャン(過去 7 日間):

Scan commits from the last 7 days on main for security vulnerabilities.

スキャンしてパッチを適用:

Run full security analysis on PR #123: scan, validate, and generate patches.

ファイル構成

.factory/
├── threat-model.md              # STRIDE threat model
├── security-config.json         # Configuration
└── security/
    ├── acknowledged.json        # Dismissed findings
    └── reports/
        └── security-report-{date}.md

検出結果の却下

PR モード - インラインコメントへの返信:

@droid dismiss reason: Input is validated by Joi schema in middleware

週次/全体モード - レポート PR へのコメント:

@droid dismiss VULN-007 reason: Accepted risk for internal admin tool

却下した検出結果は .factory/security/acknowledged.json に保存されます。

制限事項

検出できないもの:

  • ビジネスロジックの脆弱性
  • 既知のパターンがないゼロデイ脆弱性
  • コンパイル済み/圧縮済みコードの脆弱性
  • 実行時の分析が必要な問題

十分に検証できない可能性があるもの:

  • 複雑な複数サービス間のデータフロー
  • 認証状態が必要な脆弱性

参考資料

コメント