mcpField
C
code-review-security

code-review-security

github.com/hieutrtrセキュリティ8438 回インストール38 週間前に更新
リポジトリ

code-review-security について

code-review-security は、OWASP Top 10 と言語固有のリスクに基づき、プルリクエストやセキュリティ関連の変更を確認するスキルです。重大度、ファイルと行、説明、推奨策を `security-review.md` に記録します。

主な機能

  1. 01OWASP Top 10 のレビューチェックリスト
  2. 02Python と React のセキュリティ確認
  3. 03AST による Python 脆弱性スキャン
  4. 04重大度別の指摘レポート

活用シーン

  1. 01認証・認可の変更レビュー
  2. 02ユーザー入力処理の脆弱性確認
  3. 03シークレットと脆弱な依存関係の検出
  4. 04機密データを公開する API 変更の評価

インストール

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

$npx skills add https://github.com/hieutrtr/ai1-skills --skill code-review-security

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

同梱ファイルscripts/security-scan.py

詳細

コードレビューのセキュリティ

使用するタイミング

次のような場合に、このスキルを有効にしてください:

  • プルリクエストのセキュリティ脆弱性をレビューするとき
  • 認証または認可コードの変更を監査するとき
  • ユーザー入力、ファイルアップロード、外部データを扱うコードをレビューするとき
  • 新機能に OWASP Top 10 の脆弱性がないか確認するとき
  • シークレットがリポジトリにコミットされていないことを検証するとき
  • 依存関係に既知の脆弱性がないかスキャンするとき
  • 機密データを公開する API エンドポイントをレビューするとき

出力: 重大度、ファイル名と行番号、説明、推奨事項を記載した調査結果を security-review.md に書き込んでください。

次の用途ではこのスキルを使用しないでください:

  • デプロイインフラストラクチャのセキュリティ(docker-best-practices を使用してください)
  • インシデント対応の手順(incident-response を使用してください)
  • セキュリティに焦点を当てない一般的なコード品質レビュー(pre-merge-checklist を使用してください)
  • 実装コードの作成(python-backend-expert または react-frontend-expert を使用してください)

手順

OWASP Top 10 チェックリスト

すべてのプルリクエストを OWASP Top 10(2021 年版)に照らしてレビューしてください。以下の各カテゴリには、Python/FastAPI および React のコードベース向けの具体的な確認項目が含まれています。


A01:アクセス制御の不備

確認する項目:

  • エンドポイントに認可チェックがない
  • 所有権を検証せずにオブジェクトを直接参照している
  • ロールベースのフィルタリングなしでデータを公開するエンドポイント
  • 新しいルートに認証用の Depends() がない

Python/FastAPI の確認項目:

# BAD: No authorization check -- any authenticated user can access any user
@router.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    return await user_repo.get(user_id)

# GOOD: Verify the requesting user owns the resource or is admin
@router.get("/users/{user_id}")
async def get_user(
    user_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    if current_user.id != user_id and current_user.role != "admin":
        raise HTTPException(status_code=403, detail="Forbidden")
    return await user_repo.get(user_id)

レビュー用チェックリスト:

  • すべてのルートに認証がある(Depends(get_current_user))
  • リソースへのアクセスが、リクエストしたユーザーに照らして検証されている
  • 管理者専用のエンドポイントで role == "admin" が確認されている
  • リストエンドポイントがユーザーの所有権でフィルタリングされている(管理者を除く)
  • IDOR(安全でない直接オブジェクト参照)の脆弱性がない

A02:暗号化の失敗

確認する項目:

  • パスワードが平文または脆弱なハッシュ方式で保存されている
  • ログやエラーメッセージに機密データが含まれている
  • シークレット、API キー、トークンがハードコードされている
  • JWT の設定が脆弱である

Python の確認項目:

# BAD: Weak password hashing
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()

# GOOD: Use bcrypt via passlib
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
password_hash = pwd_context.hash(password)

# BAD: Secret in code
SECRET_KEY = "my-super-secret-key-123"

# GOOD: Secret from environment
SECRET_KEY = os.environ["SECRET_KEY"]

レビュー用チェックリスト:

  • パスワードが bcrypt でハッシュ化されている(MD5、SHA1、平文は使用しない)
  • JWT シークレットがハードコードされず、環境変数から読み込まれている
  • 機密データ(パスワード、トークン、PII)がログから除外されている
  • すべての外部通信で HTTPS が強制されている
  • ソースコードにシークレットがない(.env.example にプレースホルダーのみが記載されていることを確認)

A03:インジェクション

確認する項目:

  • 文字列補間を使った生の SQL クエリ
  • ユーザー入力を使った eval()、exec()、compile()
  • shell=True を指定した subprocess 呼び出し
  • テンプレートインジェクション

Python の確認項目:

# BAD: SQL injection via string formatting
query = f"SELECT * FROM users WHERE email = '{email}'"
db.execute(text(query))

# GOOD: Parameterized query
db.execute(text("SELECT * FROM users WHERE email = :email"), {"email": email})

# GOOD: SQLAlchemy ORM (always parameterized)
user = db.query(User).filter(User.email == email).first()

# BAD: Command injection
subprocess.run(f"convert {filename}", shell=True)

# GOOD: Pass arguments as a list
subprocess.run(["convert", filename], shell=False)

# BAD: Code execution with user input
result = eval(user_input)

# GOOD: Never eval user input. Use ast.literal_eval for safe parsing.
result = ast.literal_eval(user_input)  # Only for literal structures

レビュー用チェックリスト:

  • 文字列補間を使った生の SQL がない(ORM またはパラメーター化クエリを使用する)
  • 外部入力を使った eval()、exec()、compile() がない
  • 動的な引数を使った subprocess.run(..., shell=True) がない
  • 信頼できないデータに対する pickle.loads() がない
  • すべてのユーザー入力が、使用前に Pydantic スキーマで検証されている

A04:安全でない設計

確認する項目:

  • 認証エンドポイントにレート制限がない
  • ログイン失敗後のアカウントロックがない
  • 公開フォームに CAPTCHA がない
  • ビジネスロジックの不備(例:負の金額、ユーザー自身による権限昇格)

レビュー用チェックリスト:

  • ログイン、登録、パスワードリセットにレート制限がある
  • 5 回以上ログインに失敗した後、アカウントロックまたは指数バックオフが行われる
  • ビジネスロジックで制約(正の金額、有効な状態遷移)が検証される
  • 機密性の高い操作に再認証が必要である

A05:セキュリティ設定ミス

確認する項目:

  • 本番環境でデバッグモードが有効になっている
  • CORS でワイルドカード * のオリジンが設定されている
  • デフォルトの認証情報または管理者アカウントが存在する
  • スタックトレースを公開する詳細なエラーメッセージ

Python/FastAPI の確認項目:

# BAD: Wide-open CORS
app.add_middleware(CORSMiddleware, allow_origins=["*"])

# GOOD: Explicit allowed origins
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://app.example.com"],
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

# BAD: Debug mode in production
app = FastAPI(debug=True)

# GOOD: Debug only in development
app = FastAPI(debug=settings.DEBUG)  # DEBUG=False in production

レビュー用チェックリスト:

  • CORS のオリジンが明示的に指定されている(本番環境ではワイルドカードを使用しない)
  • 本番環境の設定でデバッグモードが無効になっている
  • エラーレスポンスにスタックトレースや内部の詳細が含まれていない
  • デフォルトの管理者認証情報が変更または削除されている
  • セキュリティヘッダーが設定されている(X-Content-Type-Options、X-Frame-Options など)

A06:脆弱で古いコンポーネント

レビュー用チェックリスト:

  • Python の依存関係に既知の CVE がない(pip-audit または safety check)
  • npm の依存関係に既知の CVE がない(npm audit)
  • ロックファイルで依存関係のバージョンが固定されている
  • 非推奨のパッケージが引き続き使用されていない

A07:識別および認証の不備

確認する項目:

  • 弱いパスワードポリシー
  • 有効期限のないセッショントークン
  • 管理者の操作で多要素認証が設定されていない
  • 有効期限のない JWT トークン

Python の確認項目:

# BAD: JWT without expiration
token = jwt.encode({"sub": user_id}, SECRET_KEY, algorithm="HS256")

# GOOD: JWT with expiration
token = jwt.encode(
    {"sub": user_id, "exp": datetime.utcnow() + timedelta(minutes=30)},
    SECRET_KEY,
    algorithm="HS256",
)

レビュー用チェックリスト:

  • JWT トークンに有効期限(exp クレーム)が設定されている
  • リフレッシュトークンが安全に保存され、失効できる
  • パスワードポリシーで最小文字数(12 文字以上)と複雑さが求められている
  • パスワード変更時またはログアウト時にセッションが無効化される
  • ログインエラーメッセージからユーザーを列挙できない

A08:ソフトウェアおよびデータの完全性の不備

レビュー用チェックリスト:

  • CI/CD パイプラインでアーティファクトの完全性が検証される
  • 署名または検証のないパッケージがない
  • 信頼できないデータのデシリアライズに安全な方法が使われている(pickle.loads を使用しない)
  • データベースのマイグレーションが実行前にレビューされる

A09:セキュリティログおよび監視の不備

レビュー用チェックリスト:

  • 認証イベント(ログイン、ログアウト、失敗した試行)が記録される
  • 認可の失敗がコンテキストとともに記録される
  • 機密データ(パスワード、トークン、PII)がログに含まれていない
  • ログエントリにタイムスタンプ、ユーザー ID、IP アドレス、操作が含まれている
  • 不審なパターン(総当たり攻撃、通常と異なるアクセス)に対するアラートが設定されている

A10:サーバーサイドリクエストフォージェリ(SSRF)

確認する項目:

  • ユーザーが指定した URL がサーバーサイドリクエストに使用されている
  • 任意の URL を受け付けるリダイレクトエンドポイント

Python の確認項目:

# BAD: Fetch arbitrary URL from user input
url = request.query_params["url"]
response = httpx.get(url)  # SSRF: can access internal services

# GOOD: Validate URL against allowlist
ALLOWED_HOSTS = {"api.example.com", "cdn.example.com"}
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_HOSTS:
    raise HTTPException(400, "URL not allowed")
response = httpx.get(url)

レビュー用チェックリスト:

  • 検証せずにユーザーが制御する URL へサーバーサイドリクエストを送信していない
  • 外部連携に URL の許可リストが使用されている
  • エラーメッセージで内部サービスの URL が公開されていない

Python 固有のセキュリティチェック

OWASP に加えて、Python コードで次のパターンを確認してください。

パターンリスク対策
eval(user_input)リモートコード実行削除するか、ast.literal_eval を使用する
pickle.loads(data)任意のコード実行JSON または msgpack を使用する
subprocess.run(cmd, shell=True)コマンドインジェクション引数をリストで渡し、shell=False にする
yaml.load(data)コード実行yaml.safe_load(data) を使用する
os.system(cmd)コマンドインジェクションsubprocess.run([...]) を使用する
生の SQL 文字列SQL インジェクションORM またはパラメーター化クエリを使用する
hashlib.md5(password)弱いハッシュ化passlib 経由で bcrypt を使用する
jwt.decode(token, options={"verify_signature": False})認証の回避常に署名を検証する
open(user_path)パストラバーサルパスを検証し、pathlib.resolve() を使用する
tempfile.mktemp()競合状態tempfile.mkstemp() を使用する
React 固有のセキュリティチェック
パターンリスク修正方法
dangerouslySetInnerHTMLXSSテキストコンテンツを使用するか、DOMPurify でサニタイズします
href 内の javascript:XSSURL を検証し、https: のみを許可します
window.location = userInputオープンリダイレクト許可リストと照合して検証します
localStorage へのトークンの保存XSS によるトークン窃取httpOnly Cookie を使用します
データに基づくインラインイベントハンドラーXSSReact のイベントハンドラーを使用します
eval() または Function()コード実行完全に削除します
ユーザーの HTML のレンダリングXSSサニタイズライブラリを使用します

React コードレビュー:

// BAD: XSS via dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userBio }} />

// GOOD: Sanitize first, or use text content
import DOMPurify from "dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userBio) }} />

// BETTER: Use text content when HTML is not needed
<p>{userBio}</p>

// BAD: javascript: URL
<a href={userLink}>Click</a>  // userLink could be "javascript:alert(1)"

// GOOD: Validate protocol
const safeHref = /^https?:\/\//.test(userLink) ? userLink : "#";
<a href={safeHref}>Click</a>
重大度の分類

優先順位を付けるため、検出事項を重大度で分類します。

重大度説明例SLA
Criticalリモートから悪用可能で、認証が不要なデータ侵害SQL インジェクション、RCE、認証の回避マージをブロックし、直ちに修正
High認証済みで悪用可能な権限昇格IDOR、アクセス制御の不備、XSS(格納型)マージをブロックし、リリース前に修正
Medium悪用には特定の条件が必要CSRF、XSS(反射型)、オープンリダイレクトスプリント内に修正
Low多層防御、情報提供ヘッダーの欠落、詳細すぎるエラー都合のよいときに修正
Infoベストプラクティスの推奨事項依存関係の更新、コードスタイルバックログで追跡
検出事項の報告形式

セキュリティ上の検出事項を報告する際は、一貫性を保つために次の形式を使用します。

## Security Finding: [Title]

**Severity:** Critical | High | Medium | Low | Info
**Category:** OWASP A01-A10 or custom category
**File:** path/to/file.py:42
**CWE:** CWE-89 (if applicable)

### Description
Brief description of the vulnerability and its impact.

### Vulnerable Code
```python
# The problematic code
vulnerable_function(user_input)
推奨される修正方法
# The secure alternative
safe_function(sanitize(user_input))
影響

攻撃者がこの脆弱性を悪用して実行できること。

参考資料
  • 関連する OWASP ページへのリンク
  • 関連する CWE エントリへのリンク

### Automated Scanning

Use `scripts/security-scan.py` to perform AST-based scanning for common vulnerability patterns in Python code. The script scans for:
- `eval()` / `exec()` / `compile()` calls
- `subprocess` with `shell=True`
- `pickle.loads()` on potentially untrusted data
- Raw SQL string construction
- `yaml.load()` without `Loader=SafeLoader`
- Hardcoded secret patterns (API keys, passwords)
- Weak hash functions (MD5, SHA1 for passwords)

Run: `python scripts/security-scan.py --path ./app --output-dir ./security-results`

**Dependency scanning (run separately):**
```bash
# Python dependencies
pip-audit --requirement requirements.txt --output json > dep-audit.json

# npm dependencies
npm audit --json > npm-audit.json

例

レビューコメントの例(Critical)

セキュリティ:SQL インジェクション(Critical、OWASP A03)

ファイル:app/repositories/user_repository.py:47

query = f"SELECT * FROM users WHERE name LIKE '%{search_term}%'"

これは文字列補間を使って生の SQL クエリを構築しているため、SQL インジェクションが可能です。 攻撃者は '; DROP TABLE users; -- を入力して、データを破壊できます。

修正方法: SQLAlchemy ORM のフィルタリングを使用します。

users = db.query(User).filter(User.name.ilike(f"%{search_term}%")).all()
レビューコメントの例(Medium)

セキュリティ:レート制限の欠落(Medium、OWASP A04)

ファイル:app/routes/auth.py:12

/auth/login エンドポイントにはレート制限がありません。攻撃者は無制限の速度で パスワードへの総当たり攻撃を実行できます。

修正方法: レート制限ミドルウェアを追加します。

from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)

@router.post("/login")
@limiter.limit("5/minute")
async def login(request: Request, ...):
出力ファイル

セキュリティ上の検出事項を security-review.md に書き込みます。

# Security Review: [Feature/PR Name]

## Summary
- Critical: 0 | High: 1 | Medium: 2 | Low: 1

## Findings

### [CRITICAL] SQL Injection in user search
- **File:** app/routes/users.py:45
- **OWASP:** A03 Injection
- **Description:** Raw SQL with string interpolation
- **Recommendation:** Use SQLAlchemy ORM filtering

### [HIGH] Missing authorization check
...

## Passed Checks
- No hardcoded secrets found
- Dependencies up to date

コメント