スタンドアロンモード
オーケストレーター経由ではなく直接実行する場合は、まず次の手順を実行する必要があります。
../codeprobe/shared-preamble.md(この SKILL.md の場所からの相対パスで解決します。ユーザーのプロジェクトではなく、隣接する codeprobe スキルディレクトリを基準にします)を読み、出力仕様、実行モード、制約を確認します。
- プロジェクトの技術スタックに応じて、
../codeprobe/references/(同じ基準で解決します)から該当するリファレンスファイルを読み込みます。
- ユーザーから別の指定がない限り、
full モードをデフォルトとして使用します。
セキュリティ脆弱性スキャナー
対象範囲
このサブスキルでは、次のカテゴリにわたってセキュリティ脆弱性を検出します。
- インジェクション — SQL インジェクション、コマンドインジェクション、LDAP/NoSQL インジェクション
- 認証と認可 — 認証の欠如、脆弱な認証情報、ハードコードされたシークレット、JWT の問題
- クロスサイトスクリプティング(XSS) — エスケープされていない出力、危険な HTML レンダリング
- 一括割り当て — 保護されていないモデル属性の割り当て
- クロスサイトリクエストフォージェリ(CSRF) — トークンの欠如、状態を変更するルートの保護不足
- 安全でないデシリアライズ — 信頼できないデータの安全でないデシリアライズ
- 機密データの漏えい — ログ内のシークレット、コミット済みの .env ファイル、漏えいしたスタックトレース
- アクセス制御の不備 — IDOR、ポリシー/ゲートチェックの欠如
- セキュリティ設定の不備 — 本番環境でのデバッグモード、過度に許可的な CORS、デフォルトの認証情報
検出対象外
- IP アドレスでアクセスが制限された内部管理ツール — これらには異なる脅威モデルがあり、その制限は意図的な場合があります。
- ハードコードされた値を使用するテストファイル — 偽の認証情報、トークン、API キーを含むテストフィクスチャは想定されており、適切です。
- 開発専用であることが明記された設定ファイル(例:
.env.example、docker-compose.dev.yml、tests/fixtures/ 内のファイル)。
- 既知の CVE がある依存関係 — このサブスキルは依存関係マニフェストではなく、ソースコードを分析します。依存関係のスキャンには専用ツール(例:
npm audit、composer audit)を使用してください。
検出手順
インジェクション
| ID プレフィックス | 検出対象 | 検出方法 | 深刻度 |
|---|
SEC | 文字列連結/補間を使った生の SQL | SQL キーワード(SELECT、INSERT、UPDATE、DELETE、WHERE)と、文字列連結(.、+、f"、${}、"${)、テンプレートリテラル、または変数補間の組み合わせを検索します。ユーザー入力がパラメーター化されずにクエリ文字列に流れ込んでいることを確認します。 | Critical |
SEC | ユーザー入力を使った DB::raw()/生のクエリ | DB::raw()、DB::select(DB::raw(、knex.raw()、sequelize.literal()、cursor.execute(f" などの生のクエリメソッドを検索します。引数に、ユーザー入力(リクエストパラメーター、フォームデータ、クエリ文字列)に由来する可能性のある変数が含まれる場合は、検出対象とします。 | Critical |
SEC | サニタイズされていない入力を使ったシェルコマンドの構築 | exec()、system()、shell_exec()、popen()、subprocess.call()、subprocess.run()、child_process.exec()、バッククォート演算子を検索します。エスケープや許可リストによる検証を行わずに、コマンド文字列にユーザー入力由来の変数が含まれる場合は、検出対象とします。 | Critical |
SEC | LDAP/NoSQL インジェクションの攻撃経路 | 文字列連結による LDAP フィルターの構築や、$where、$regex、その他の任意の式を受け入れる演算子にユーザー入力を使った MongoDB クエリの構築を検索します。 | Critical |
認証と認可
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | データを変更するルートに認証ミドルウェアがない | ルート定義(例:Route::post()、router.post()、@app.post())をスキャンし、POST/PUT/PATCH/DELETE エンドポイントを確認します。認証ミドルウェアが適用されているか確認します。認証レイヤーなしでデータを変更するルートにフラグを付けます。 | 致命的 |
SEC | ロールチェックがビュー/フロントエンドで行われ、バックエンドでは行われていない | フロントエンドのテンプレートまたは JavaScript でロール/権限チェック(例:v-if="user.isAdmin"、{user.role === 'admin' && ...})を検索し、対応するバックエンドのエンドポイントでもチェックが適用されているか確認します。バックエンドにない場合はフラグを付けます。 | 重大 |
SEC | ソースコード内にシークレット/API キーがハードコードされている | 次のパターンを検索します:api_key = "..."、secret = '...'、password = "..."、token = '...'、AWS_SECRET、STRIPE_KEY、ベアラートークンなど。.env.example ファイルとテスト用フィクスチャは除外します。シークレットらしい名前の変数に割り当てられた、高エントロピーの文字列を確認します。 | 致命的 |
SEC | パスワードポリシーが弱い | ユーザー登録/パスワード変更のロジックを確認します。パスワードの検証で最小文字数(8 文字以上)や複雑さが強制されているか、または検証ライブラリが使われているか確認します。検証ルールなしでパスワードが受け入れられる場合はフラグを付けます。 | 重大 |
SEC | 有効期限のない JWT | JWT の作成/署名コードを検索します。ペイロードに exp(有効期限)クレームが含まれているか確認します。有効期限なしで作成された JWT、または有効期限が過度に長い(アクセストークンで 24 時間を超える)JWT にフラグを付けます。 | 重大 |
クロスサイトスクリプティング(XSS)
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | Laravel Blade でユーザーデータに {!! !!}(エスケープされない出力)を使用している | .blade.php ファイルで {!! ... !!} を検索します。内容がユーザー入力、ユーザー提供 HTML を保存するデータベースフィールド、またはリクエストデータに由来するか確認します。静的コンテンツと、信頼された管理者専用フィールドは除外します。 | 重大 |
SEC | React で信頼できないデータに dangerouslySetInnerHTML を使用している | .jsx/.tsx ファイルで dangerouslySetInnerHTML を検索します。__html の値がユーザー入力、サニタイズされていない API レスポンス、または DOMPurify などで明示的にサニタイズされていないソースに由来するか確認します。 | 重大 |
SEC | Vue で信頼できないデータに v-html を使用している | .vue ファイルで v-html ディレクティブを検索します。上記と同じ分析を行い、バインドされた値にサニタイズされていないユーザー入力が含まれる可能性がある場合はフラグを付けます。 | 重大 |
SEC | Content-Security-Policy がない | ミドルウェア、ウェブサーバー設定、またはメタタグに CSP ヘッダーがあるか確認します。プロジェクト内のどこにも CSP が設定されていない場合、多層防御の不足としてフラグを付けます。 | 軽微 |
マスアサインメント
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | $fillable または $guarded がない Laravel モデル | Eloquent モデルクラス(Model を継承)を検索します。各モデルで $fillable(許可リスト)または $guarded(ブロックリスト)のいずれかのプロパティが定義されているか確認します。どちらも定義されていないモデルにフラグを付けます。 | 重大 |
SEC | $request->all() を create/update に渡している | $request->all()、request.body(分割代入なし)、**request.data が Model::create()、Model::update()、Model::fill()、または ORM の create/update メソッドに直接渡されている箇所を検索します。マスアサインメントの攻撃経路としてフラグを付けます。 | 致命的 |
クロスサイトリクエストフォージェリ(CSRF)
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | CSRF トークンのないフォーム | method="POST"(または PUT/PATCH/DELETE)を指定した <form タグを検索します。フォームに CSRF トークンフィールド(@csrf、csrf_token()、csrfmiddlewaretoken、_token)が含まれているか確認します。トークンのないフォームを報告します。 | 重大 |
SEC | 状態を変更する API ルートに適切な認証がない | CSRF 保護と認証ミドルウェアの両方がない API ルート(POST/PUT/PATCH/DELETE)を確認します。トークン認証を使用するステートレス API は問題ありませんが、CSRF トークンのないセッションベースの API は問題です。 | 重大 |
安全でないデシリアライゼーション
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | ユーザー入力に対する unserialize() | unserialize()(PHP)、pickle.loads()(Python)、ObjectInputStream(Java)、Marshal.load(Ruby)を検索します。入力元がユーザー制御可能な場合(リクエスト本文、Cookie、クエリパラメーター、アップロードファイル)に報告します。 | 致命的 |
SEC | 検証せずに eval 相当のコンテキストで使用される JSON.parse() | 外部データに対する JSON.parse() を検索し、解析結果が eval()、Function()、setTimeout(string) に渡されている場合や、コードの動的な構築に使用されている場合を確認します。JSON.parse 自体ではなく、eval 相当の使用箇所を報告します。 | 重大 |
機密データの漏えい
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | ログ出力に含まれるパスワード/トークン | password、token、secret、key、credential、auth などの名前の変数を含むログ出力呼び出し(Log::、logger.、console.log、print、logging.)を検索します。機密データがログに書き込まれている場合に報告します。 | 致命的 |
SEC | .env が git にコミットされている | .gitignore に .env が含まれているか確認します。リポジトリに .env が存在し、gitignore の対象になっていない場合は、致命的な問題として報告します。コミット済みの .env.production と .env.staging も確認します。 | 致命的 |
SEC | 環境変数ではなく設定ファイルに含まれるシークレット | 設定ファイルでハードコードされた認証情報、API キー、データベースパスワードを検索します。環境変数から取得すべき値が、追跡対象の設定ファイルにハードコードされている場合に報告します。 | 重大 |
SEC | 本番環境の設定でスタックトレースを漏らすエラーメッセージ | エラー/例外処理の設定を確認します。レスポンスでスタックトレース、ファイルパス、SQL クエリを公開する APP_DEBUG=true、DEBUG=True、display_errors=On、またはカスタムエラーハンドラーを探します。これらが本番環境の設定にある場合に報告します。 | 重大 |
アクセス制御の不備
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | IDOR — 所有権を確認せずにユーザー提供の ID を使用 | 認証済みユーザーがリソースを所有していることを確認せずに、リソースの取得に使用されているルートパラメーターやリクエストパラメーター(例:$request->id、params.id、request.args.get('id'))を検索します。where('user_id', auth()->id()) やポリシーによるチェックを行わない Model::find($id) を探します。 | 致命的 |
SEC | リソースアクセスに対するポリシー/ゲートのチェック不足 | 認可システムを備えたフレームワーク(Laravel のポリシー、Django の権限、Express のミドルウェア)では、ユーザー所有のリソースに対する CRUD 操作に認可チェックが含まれているか確認します。ポリシーや権限の確認なしにリソースを読み取り/変更するコントローラーのアクションを報告します。 | 重大 |
セキュリティ設定の不備
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|
SEC | 本番環境の設定における APP_DEBUG=true | 本番環境の設定と思われる設定ファイルで、APP_DEBUG=true、DEBUG=True、debug: true を検索します(.env.example や .env.local は対象外です)。 | Major |
SEC | 許可範囲が広すぎる CORS | CORS の設定を検索します。公開 API 以外のコンテキストで Access-Control-Allow-Origin: * または allowed_origins: ['*'] があれば、問題として報告します。また、ワイルドカードのオリジンと Access-Control-Allow-Credentials: true の併用も報告します。 | Major |
SEC | 設定内のデフォルト認証情報 | 設定ファイル、シーダー、初期化コードで、admin、root、test などのユーザー名と、password、123456、admin、secret、changeme などのパスワードの組み合わせを検索します。テスト用フィクスチャは対象外です。 | Critical |
ID Prefix と修正プロンプトの例
すべての検出事項には SEC- プレフィックスを付け、SEC-001、SEC-002 などと連番を振ります。
修正プロンプトの例
- "
UserController@update(34 行目)で、マスアサインメントによる is_admin フィールドへの代入を防ぐため、$request->all() を $request->only(['name', 'email']) に置き換えてください。また、まだ設定されていない場合は、User モデルに $fillable = ['name', 'email'] を追加してください。"
- "
app/Services/SearchService.php の 55 行目で、ユーザー入力をプレースホルダーを使ったクエリに変更してください。DB::select(\"SELECT * FROM products WHERE name LIKE '%$search%'\") を DB::select('SELECT * FROM products WHERE name LIKE ?', [\"%{$search}%\"]) に置き換えてください。"
- "
routes/api.php で、22 行目の POST /api/orders ルートに認証ミドルウェアを追加してください。Route::post('/orders', [OrderController::class, 'store']) を Route::post('/orders', [OrderController::class, 'store'])->middleware('auth:sanctum') に変更してください。"
- "
config/services.php の 15 行目にハードコードされている API キーを環境変数に移してください。'key' => 'sk-live-abc123...' を 'key' => env('STRIPE_SECRET_KEY') に置き換え、.env.example に STRIPE_SECRET_KEY= を追加してください。"