sast-hardcodedsecrets について
公開アクセス可能なコードに含まれるハードコードされたシークレットを探すセキュリティレビュー用スキルです。クライアント側とバックエンド専用箇所を区別し、候補をバッチ検証して結果を統合します。事前に `sast/architecture.md` が必要です。
主な機能
- 01シークレット候補の検出
- 02公開コードでの露出評価
- 03候補のバッチ検証
- 04分析結果レポートの統合
活用シーン
- 01フロントエンドバンドルの認証情報監査
- 02モバイルコード内の埋め込みシークレット確認
- 03クライアント露出項目とバックエンド専用値の分類
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ utkusen/ sast-skills --skill sast-hardcodedsecretsインストール後、Claude Code で/sast-hardcodedsecretsを入力して読み込まれたか確認します。
詳細
パブリックコード内のハードコードされたシークレットの検出
公開されているコードに露出したハードコード済みの機密データを見つけることを目的とした、対象を絞ったセキュリティ評価を行います。このスキルでは、サブエージェントを使った3段階のアプローチを採用します。recon(シークレット候補をすべて検出)、batched verify(公開アクセス可能なコード内の本物のシークレットかどうかを、3件ずつ並列で検証)、merge(各バッチのレポートを1つのファイルに統合)です。
前提条件:sast/architecture.mdが存在している必要があります。存在しない場合は、先に分析スキルを実行してください。
パブリックコード内のハードコードされたシークレットとは
ハードコードされたシークレットとは、APIキー、アクセストークン、秘密鍵、パスワード、署名シークレット、データベース接続文字列など、ソースコードに文字列リテラルとして直接埋め込まれた機密性の高い認証情報です。
このスキルは特に、攻撃者がサーバー側にアクセスすることなく抽出できる、公開アクセス可能なコードに含まれるシークレットに焦点を当てています。バックエンドのサーバーコードにハードコードされたシークレットは望ましくありませんが、デプロイ済みアプリケーションを調べる外部の攻撃者が直接悪用することはできません。フロントエンドのJavaScriptやモバイルアプリのバイナリにハードコードされたシークレットは、直接抽出できます。
核心となる問い:外部の攻撃者は、サーバーにアクセスすることなく、デプロイ済みアプリケーションからこのシークレットを入手できますか?
報告対象(公開アクセス可能なコード)
以下のコードパスは、デプロイ後に攻撃者がアクセスできます。
- フロントエンドのJavaScript/TypeScript — ブラウザーで実行される
.js、.ts、.jsx、.tsxファイル。以下が含まれます。- React、Angular、Vue、Svelteのコンポーネントやページ
- Next.jsのクライアントコンポーネント(
"use client"を含むファイル、または"use server"を含まないapp/配下のファイル) - Nuxt.jsのページとクライアントプラグイン
public/、static/、assets/ディレクトリ内のバニラJS- Webpack/Vite/Rollupのエントリーポイントと、それらがインポートするモジュール
- クライアント側のエントリーポイントからインポートされるファイル(
utils/やlib/フォルダー内にある場合も含む)
- モバイルアプリケーションのコード — リバースエンジニアリングで抽出可能なコード(APKの逆コンパイル、IPAの検査など)。
- Android:Java/Kotlinのソースファイル
- iOS:Swift/Objective-Cのソースファイル
- React Native:JavaScriptバンドル
- Flutter:Dartのソースファイル
- Xamarin:C#のソースファイル
- クライアントに配信されるHTMLファイルとテンプレート — インラインの
<script>ブロック、data-属性、メタタグ - クライアント側の設定ファイル —
public/、static/、assets/、www/ディレクトリ内のファイル - Electron/デスクトップアプリのソース — ASARアーカイブから抽出可能なもの
- WebAssemblyのソース/付随するJS — JSのグルーコード内のシークレット、またはWASMから抽出可能なシークレット
報告対象外(バックエンド専用コード)
以下の場所にあるシークレットは公開アクセスできないため、指摘しないでください。
- サーバー側のアプリケーションコード — Expressのルートハンドラー(サーバー専用)、Djangoのビュー、Flaskのルート、Springのコントローラー、Railsのコントローラー、GoのHTTPハンドラー、PHPのコントローラーなど、サーバー上でのみ実行されるコード
- サーバー側のAPIルートファイル — Next.jsの
app/api/ルート、Nuxtのサーバールート、SvelteKitの+server.tsファイル - 環境ファイル —
.env、.env.local、.env.production(静的に配信される場合を除く) - サーバー側の設定ファイル —
config/database.yml、settings.py、application.properties、appsettings.json - CI/CDパイプラインのファイル —
.github/workflows/、Jenkinsfile、.gitlab-ci.yml - Docker/インフラストラクチャのファイル —
Dockerfile、docker-compose.yml、Kubernetesのマニフェスト - バックエンドのユーティリティ/サービスファイル — サーバー側のコードからのみインポートされるファイル
- テストファイル — テスト用フィクスチャとテスト設定(テストファイルがクライアントに配布される場合を除く)
- マイグレーションファイル — データベースのマイグレーション
フロントエンドとバックエンドの区別
これは非常に重要であり、プロジェクトのアーキテクチャを理解する必要があります。
Next.js:app/ 配下のファイルで、"use client" ディレクティブがあるもの、または"use server" がないものはクライアントコンポーネントです。app/api/ 配下のファイルはサーバー専用です。pages/api/ 配下のファイルはサーバー専用です。pages/ 配下のファイル(api 以外)はサーバーとクライアントの両方でレンダリングされるため、ここにあるシークレットは公開されます。next.config.js はサーバー側でのみ実行されますが、NEXT_PUBLIC_* 環境変数はクライアントバンドルに埋め込まれます。
Nuxt.js:pages/、components/、composables/ 配下のファイルにはクライアントからアクセスできます。server/ 配下のファイルはサーバー専用です。
React(CRA/Vite):src/ 内のすべてがクライアント向けにバンドルされます。REACT_APP_* と VITE_* 環境変数はクライアントビルドに埋め込まれます。
Angular:src/ 内のすべてがクライアント向けにバンドルされます。
Vue(Vite):src/ 内のすべてがクライアント向けにバンドルされます。VITE_* 環境変数は埋め込まれます。
Express/Fastify/Koa:public/ または static/ ディレクトリから静的ファイルを配信する場合を除き、すべてサーバー側です。
Django/Flask:Python コードはサーバー側です。テンプレートはサーバー側でレンダリングされます(テンプレートコンテキスト内のシークレットは、明示的に JS にレンダリングしない限りクライアントには届きません)。static/ 内の静的ファイルにはクライアントからアクセスできます。
Rails:Ruby コードはサーバー側です。app/assets/javascripts/ または app/javascript/ 内のアセットにはクライアントからアクセスできます。
モバイルアプリ:リバースエンジニアリングによって、すべてのソースコードに公開状態でアクセスできるものと見なしてください。
確認するシークレットの種類
確度の高いパターン(正規表現で識別可能)
これらは特徴的な形式を持つため、高い確度で識別できます。
| シークレットの種類 | パターン |
|---|---|
| AWS アクセスキー ID | AKIA[0-9A-Z]{16} |
| AWS シークレットアクセスキー | AKIA キーの近くにある40文字の base64 文字列 |
| Google API キー | AIza[0-9A-Za-z\\-_]{35} |
| Google OAuth クライアントシークレット | GOCSPX-[0-9A-Za-z\\-_]{28} |
| GitHub 個人用アクセストークン | ghp_[0-9A-Za-z]{36}, github_pat_[0-9A-Za-z_]{82} |
| GitHub OAuth アプリシークレット | gho_[0-9A-Za-z]{36} |
| GitLab 個人用アクセストークン | glpat-[0-9A-Za-z\\-_]{20} |
| Slack ボット/ユーザートークン | xoxb-[0-9A-Za-z\\-]+, xoxp-[0-9A-Za-z\\-]+ |
| Slack Webhook URL | hooks.slack.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+ |
| Stripe シークレットキー | sk_live_[0-9A-Za-z]{24,} |
| Stripe 公開可能キー | pk_live_[0-9A-Za-z]{24,}(公開可能キーはクライアント側で使用するよう設計されています。シークレットキーと組み合わされていない限り、対象外にしてください) |
| Twilio アカウント SID と認証トークン | AC[0-9a-f]{32}(SID)、近くにある32桁の16進数の認証トークン |
| SendGrid API キー | SG\.[0-9A-Za-z\\-_]{22}\.[0-9A-Za-z\\-_]{43} |
| Mailgun API キー | key-[0-9a-zA-Z]{32} |
| Firebase 設定 | 設定オブジェクト内に apiKey、authDomain、projectId がそろっている場合。標準のクライアント設定ではなく、サーバー/管理者キーが含まれている場合のみ対象にしてください |
| RSA/EC/SSH 秘密鍵 | `-----BEGIN (RSA |
| JWT シークレット/署名キー | JWT_SECRET、jwt_secret、signingKey、HMAC_KEY などの変数に代入されている文字列 |
| パスワードを含むデータベース接続文字列 | postgresql://user:pass@、mysql://user:pass@、mongodb://user:pass@、redis://:pass@ |
| 汎用 API キーの代入 | *api_key*、*apiKey*、*API_KEY*、*secret*、*SECRET*、*token*、*TOKEN*、*password*、*PASSWORD* という名前の変数に、実際の認証情報に見える文字列リテラルが代入されている場合 |
| Heroku API キー | Heroku のコンテキストにある [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} |
| Azure ストレージキー | ストレージアカウントのキ変数に代入された約88文字の base64 文字列 |
| OpenAI API キー | sk-[A-Za-z0-9]{48} または sk-proj-[A-Za-z0-9\\-_]{100,} |
| Anthropic API キー | sk-ant-[A-Za-z0-9\\-_]{90,} |
変数名のパターン(値の確認が必要)
次の名前のパターンに一致する変数や定数を検索し、割り当てられた値が実際の認証情報のように見えるか確認してください。
api_key,apiKey,API_KEY,ApiKeysecret,SECRET,secret_key,secretKey,SECRET_KEYaccess_token,accessToken,ACCESS_TOKENauth_token,authToken,AUTH_TOKENprivate_key,privateKey,PRIVATE_KEYpassword,PASSWORD,passwd,PASSWDclient_secret,clientSecret,CLIENT_SECRETsigning_key,signingKey,SIGNING_KEYencryption_key,encryptionKey,ENCRYPTION_KEYbearer_token,BEARER_TOKENcredentials,CREDENTIALSconnection_string,connectionString,DATABASE_URL
実際のシークレットではないもの(誤検知として無視する項目)
- プレースホルダー値:"your-api-key-here"、"TODO"、"xxx"、"changeme"、"REPLACE_ME"、"INSERT_KEY"、"<api_key>"、"dummy"、"test"、"example"、"sample"、"placeholder"
- 空文字列:
""、'' - 環境変数への参照:
process.env.API_KEY、os.environ["SECRET"]、ENV["KEY"]— これらは実行時に環境から値を読み取り、値がハードコードされているわけではありません - 公開鍵:公開鍵は(秘密鍵ではなく)共有することを想定しているため、シークレットではありません
- 公開可能な API キー/パブリッシャブルキー:Stripe の
pk_test_*、pk_live_*、Firebase クライアント設定のapiKey(クライアント側での使用を想定)、Google Maps クライアントキー(HTTP リファラーで制限) - テスト/開発用キー:
sk_test_*(Stripe のテストキー)、テスト用フィクスチャとして明確に名付けられたファイル内のキー - 型定義/インターフェース:TypeScript の
interface Config { apiKey: string }— 実際の値はありません - ドキュメント文字列:キーの形式を説明するコメント
- ハッシュ値:シークレットではない SHA256/MD5 ハッシュ(例:コンテンツハッシュ、チェックサム)
- ビルド時定数:バージョン文字列、ビルド ID、コミットハッシュ
実行
このスキルはサブエージェントを使用して、3 つのフェーズで実行されます。sast/architecture.md の内容をすべてのサブエージェントにコンテキストとして渡してください。
Phase 1: 調査 — 秘密情報の候補を探す
次の指示を与えてサブエージェントを起動します。
目標:コードベース内で、ハードコードされた秘密情報(API キー、アクセストークン、秘密鍵、パスワード、署名用シークレット、接続文字列)が文字列リテラルとして現れる場所をすべて見つけてください。結果を
sast/hardcodedsecrets-recon.mdに書き出してください。コンテキスト:プロジェクトのアーキテクチャ概要が提供されます。それを使って、技術スタックやプロジェクト構成、フロントエンドとバックエンドのファイルを把握してください。
検索対象:
コードベース全体をスキャンしてください。この段階では、フロントエンドコードかバックエンドコードかに関係なく、秘密情報の可能性があるものをすべて報告してください。絞り込みは Phase 2 で行います。
- 確度の高い正規表現パターン — 次の特徴的な形式を検索してください。
- AWS キー:
AKIA[0-9A-Z]{16}- Google API キー:
AIza[0-9A-Za-z\-_]{35}- GitHub トークン:
ghp_、github_pat_、gho_、ghs_- Slack トークン:
xoxb-、xoxp-、xoxa-、xoxr-- Stripe シークレットキー:
sk_live_、sk_test_- SendGrid キー:
SG\.- OpenAI キー:
sk-に続く48文字以上の英数字- Anthropic キー:
sk-ant-- 秘密鍵ヘッダー:
-----BEGIN.*PRIVATE KEY------ パスワードが埋め込まれた接続文字列:
://[^:]+:[^@]+@- 変数代入パターン — 秘密情報に関連する名前の変数に、文字列リテラル値が代入されている箇所を検索してください。
- 次のようなパターンを検索してください:
apiKey = "..."、api_key = '...'、API_KEY: "..."、secret: "..."、token = "..."、password = "..."、client_secret = "..."- camelCase、snake_case、SCREAMING_SNAKE_CASE、PascalCase など、すべての命名規則を対象にしてください。
- JS/TS オブジェクト、JSON ファイル、YAML/TOML 設定ファイル、Python 辞書、環境変数形式の設定ファイルを調べてください。
- 既知のキー形式に一致するインライン文字列リテラル:
- 認証関連の変数に代入された、長いランダムな英数字列(32文字以上)
- 認証コンテキスト内の Base64 エンコード文字列
- キーまたは秘密情報として使われている16進文字列(64文字以上)
- API キーまたは秘密情報として使われている UUID
調査時に除外するもの:
- 環境変数の読み取り:
process.env.*、os.environ[*]、ENV[*]、System.getenv(*)— これらはハードコードされていません。- 値のない型定義:
apiKey: string、type Config = { secret: string }- 明らかなプレースホルダー:
"your-key-here"、"TODO"、"xxx"、"changeme"、"REPLACE_ME"、"<api_key>"、"dummy"、"test-key"、"example"、"sample"、空文字列- 秘密情報について説明または記述しているだけのコメント
- 公開鍵(秘密ではない暗号鍵)
- チェックサムまたはコンテンツ識別子として使われているハッシュ値
.git/、node_modules/、vendor/、venv/、__pycache__/、dist/、build/ディレクトリ内のファイル出力形式 —
sast/hardcodedsecrets-recon.mdに書き出してください。# ハードコードされた秘密情報の調査:[プロジェクト名] ## 概要 秘密情報がハードコードされている可能性のある候補が [N] 件見つかりました。 ## 候補 ### 1. [内容が分かる名前 — 例:「API 設定内の AWS アクセスキー」] - **ファイル**:`path/to/file.ext`(行 X-Y) - **秘密情報の種類**:[AWS キー / Google API キー / 汎用 API キー / 秘密鍵 / パスワード / JWT シークレット / 接続文字列 / など] - **変数/コンテキスト**:[秘密情報が現れる変数名またはコンテキスト] - **検出方法**:[正規表現の一致 / 変数名パターン / インラインリテラル] - **コードスニペット**:[秘密情報を含む行を表示 — 実際の値の中間部分を伏せてください。例:「AKIA****EXAMPLE」または「sk_live_****abcd」]
[候補ごとに繰り返す]
フェーズ 1 の後:続行する前に候補を確認する
フェーズ 1 の完了後、sast/hardcodedsecrets-recon.md を読みます。調査で候補が 0 件見つかった場合(概要に「Found 0」と記載されている、または「Candidates」セクションが空か存在しない場合)は、フェーズ 2 とフェーズ 3 を完全にスキップします。その代わりに、次の内容を sast/hardcodedsecrets-results.md に書き込み、終了します。
# Hardcoded Secrets Analysis Results
No vulnerabilities found.
フェーズ 2 に進むのは、フェーズ 1 で候補が 1 件以上見つかった場合に限ります。
フェーズ 2:検証 — 公開コード内の実際のシークレットを確認する(バッチ処理)
フェーズ 1 の完了後、sast/hardcodedsecrets-recon.md を読み、候補を最大 3 件ずつのバッチに分けます。バッチごとにサブエージェントを 1 つ並列で起動します。各サブエージェントは割り当てられた候補のみを検証し、結果を独自のバッチファイルに書き込みます。
バッチ分割手順(サブエージェントではなく、あなた(オーケストレーター)が実行します):
sast/hardcodedsecrets-recon.mdを読み、番号付きの候補セクション(### 1.、### 2. など)の数を数えます。- 候補を最大 3 件ずつのバッチに分けます。例:候補が 8 件の場合は、3 つのバッチ(1~3、4~6、7~8)に分けます。
- 各バッチについて、調査ファイルから該当する候補セクションの全文を抽出します。
- すべてのバッチサブエージェントを並列で起動し、それぞれに割り当てられた候補のみを渡します。
- 各サブエージェントは
sast/hardcodedsecrets-batch-N.mdに書き込みます。N は 1 から始まるバッチ番号です。
各バッチサブエージェントに、次の指示を与えます(バッチ固有の値に置き換えてください)。
目標:以下のハードコードされたシークレット候補を検証します。それぞれについて、(1)実際のシークレットか、(2)公開アクセス可能なコードに含まれているかを判定します。結果を
sast/hardcodedsecrets-batch-[N].mdに記載してください。担当する候補(偵察フェーズより):
[担当候補のセクション全文を、元の番号を維持して貼り付けてください]
コンテキスト:プロジェクトのアーキテクチャ概要が提供されます。これを使って、技術スタック、フロントエンドとバックエンドの分離、ビルドパイプライン、クライアント側コードとサーバー側コードが含まれるディレクトリを把握してください。
候補ごとに、次の2つの質問に回答してください。
質問1:実際のシークレットですか?
値が実際の認証情報か、誤検知かを確認します。
- 文字列に実際のキー/トークンのエントロピーと形式がありますか?(実際の API キーは通常、20 文字以上のランダムな文字列です)
- 既知のプレースホルダーやサンプル値ですか?(「your-key-here」、「changeme」、「test」、「example」、「TODO」、「xxx」、「REPLACE_ME」など)
- テスト/開発用キーですか?(Stripe の
sk_test_*、サンドボックス認証情報、テスト用フィクスチャ内のキー)- 設計上、公開可能なキーですか?(Stripe の
pk_live_*、Firebase クライアントのapiKey、Google Maps のブラウザーキー)- 誤って検出された環境変数の参照ですか?
- ハッシュ、チェックサム、または機密ではない識別子ですか?
値が実際のシークレットではない場合は、Not Vulnerable と分類し、その理由を説明してください。
質問2:公開アクセス可能なコードに含まれていますか?
外部の攻撃者が、デプロイ済みアプリケーションからこのシークレットを取得できるか判定します。
公開アクセス可能(報告対象):
- ブラウザーで実行されるフロントエンドの JavaScript/TypeScript(React、Angular、Vue、Svelte のコンポーネント/ページ)
- Next.js のクライアントコンポーネント(
"use client"を含むファイル、またはクライアントでレンダリングされるページ)- Nuxt.js の
pages/、components/、クライアント側のplugins/- クライアント側のエントリーポイントからインポートされる
.js/.tsファイル(インポートチェーンを追跡してください)- 直接配信される
public/、static/、assets/、www/ディレクトリ内のファイル- インラインの
<script>ブロックを含む HTML ファイル- モバイルアプリのソースコード — Android(Java/Kotlin)、iOS(Swift/Objective-C)、React Native JS、Flutter Dart、Xamarin C# — すべてのモバイルコードはリバースエンジニアリングで抽出可能です
- Electron アプリのソース(ASAR から抽出可能)
- JavaScript に埋め込まれたクライアント側の設定オブジェクト(Firebase 設定、アナリティクスの初期化など)
公開アクセス不可(報告対象外):
- サーバー側のルートハンドラー(Express、Django、Flask、Rails、Spring、Go、PHP のコントローラー)
- サーバー側の API ルート(Next.js の
app/api/、Nuxt のserver/、SvelteKit の+server.ts)- サーバー側コードからのみインポートされるバックエンドサービス、ミドルウェア、ユーティリティ
.envファイル、サーバー設定ファイル、Docker/CI ファイル- クライアントに配信されないテストファイルやフィクスチャ
- データベースのマイグレーション
- ビルドスクリプトやツール
ファイルがクライアント側かどうかの判断方法:
- ファイルパスを確認します — クライアント側のディレクトリ配下にありますか?(CRA/Vite React の
src/、Next.js のpages/、Angular のapp/、Vue のsrc/)- インポートチェーンを追跡します — このファイルはクライアント側のエントリーポイントから直接的または間接的にインポートされていますか?
- サーバー専用の目印を確認します —
"use server"ディレクティブ、またはapi/やserver/ディレクトリ配下のファイルですか?- プロジェクトのフロントエンド/バックエンド分離パターンについては
sast/architecture.mdを確認します- 判断が曖昧な場合(例:共有ユーティリティファイル)は、慎重な側に倒してください — クライアント向けにバンドルされる可能性がある場合は、公開アクセス可能として扱います
シークレットが公開アクセス可能なコードに含まれていない場合は、Not Vulnerable と分類し、その理由を説明してください(例:「サーバー側のみ — Express のルートハンドラー」)。
分類:
- Vulnerable:実際のシークレットであることが確認され、公開アクセス可能なコードに含まれていることも確認済みです。攻撃者はデプロイ済みアプリケーションからこれを取得できます。
- Likely Vulnerable:実際のシークレットである可能性が高く、ファイルもクライアントからアクセス可能と考えられますが、どちらか一方、または両方の条件を完全には確認できません(例:インポートチェーンが曖昧、本番用キーかどうか不明)。
- Not Vulnerable:実際のシークレットではない(プレースホルダー、テストキー、公開キー)か、公開アクセス可能なコードに含まれていません(バックエンドのみ)。
- Needs Manual Review:値が実際のシークレットか、ファイルがクライアントに配信されるかを判断できず、人による確認が必要です。
出力形式 —
sast/hardcodedsecrets-batch-[N].mdに記載してください。# ハードコードされたシークレット バッチ [N] の結果 ## 検出結果 ### [VULNERABLE] 説明的な名前 - **ファイル**: `path/to/file.ext`(行 X-Y) - **シークレットの種類**: [AWS キー/Google API キーなど] - **露出経路**: [攻撃者が取得する方法 — 例:「Webpack 経由でクライアント JS にバンドルされ、ブラウザーの DevTools の Sources タブで確認可能」または「Android APK に埋め込まれており、`apktool d app.apk` で抽出可能」] - **問題**: [明確な説明 — 例:「AWS アクセスキーがブラウザー向けにバンドルされる React コンポーネントにハードコードされている」] - **影響**: [攻撃者がこのシークレットを使ってできること — 例:「AWS S3 バケットへの完全なアクセスと、データ窃取の可能性」、「組織に代わって SendGrid 経由でメールを送信」、「API 経由でユーザーデータにアクセス」] - **証拠**:[シークレット値を一部マスクしたコードスニペット]
- **修正方法**: [シークレットをサーバー側の環境変数に移してください。クライアントからこの API を呼び出す必要がある場合は、バックエンドをプロキシとして経由させてください。モバイルアプリでは、キーを埋め込むのではなく、バックエンドプロキシまたは OAuth フローを使用してください。] - **確認手順**:[この検出結果を確認する方法:
- Web アプリの場合:「ブラウザーの DevTools > Sources を開き、バンドルされた JS ファイル内で 'AKIA' を検索」
- モバイルアプリの場合:「
apktool d app.apkを実行し、キーのパターンを grep で検索」- Electron の場合:「ASAR アーカイブを展開し、キーを検索」]
### [LIKELY VULNERABLE] 説明的な名前 - **ファイル**: `path/to/file.ext`(行 X-Y) - **シークレットの種類**: [種類] - **露出経路**: [クライアントに配信される経路の推定] - **問題**: [不確かな点] - **懸念事項**: [それでもリスクがある理由] - **証拠**:[コードスニペット]
- **修正方法**: [修正の推奨事項] ### [NOT VULNERABLE] 説明的な名前 - **ファイル**: `path/to/file.ext`(行 X-Y) - **理由**: [例:「プレースホルダー値 — 'your-api-key-here'」、「サーバー側のみ — Django ビューであり、クライアントには配信されない」、「Stripe の公開可能キー — クライアントでの使用を想定したもの」] ### [NEEDS MANUAL REVIEW] 説明的な名前 - **ファイル**: `path/to/file.ext`(行 X-Y) - **不確実な点**: [自動解析でステータスを判定できなかった理由] - **提案**: [手動で確認する内容]
フェーズ 3:マージ — バッチ結果を統合する
すべてのフェーズ 2 のバッチサブエージェントが完了したら、すべての sast/hardcodedsecrets-batch-*.md ファイルを読み込み、1 つの sast/hardcodedsecrets-results.md に統合します。この作業はオーケストレーターが直接行い、サブエージェントは必要ありません。
マージ手順:
sast/hardcodedsecrets-batch-1.md、sast/hardcodedsecrets-batch-2.md、... のすべてのファイルを読み込みます。- 各バッチファイルからすべての検出結果を集め、元の分類とすべての詳細項目を維持したまま、1 つのリストにまとめます。
- エグゼクティブサマリー用に、すべてのバッチの合計数を集計します。
- 次の形式を使用して、統合レポートを
sast/hardcodedsecrets-results.mdに書き込みます。
# Hardcoded Secrets Analysis Results: [Project Name]
## Executive Summary
- Candidates analyzed: [total across all batches]
- Vulnerable: [N]
- Likely Vulnerable: [N]
- Not Vulnerable: [N]
- Needs Manual Review: [N]
## Findings
[All findings from all batches, grouped by classification:
VULNERABLE first, then LIKELY VULNERABLE, then NEEDS MANUAL REVIEW, then NOT VULNERABLE.
Preserve every field from the batch results exactly as written.]
sast/hardcodedsecrets-results.mdの書き込み後、すべての中間バッチファイル(sast/hardcodedsecrets-batch-*.md)を削除します。
重要な注意事項
sast/architecture.mdを読み込み、その内容をすべてのサブエージェントにコンテキストとして渡してください。- フェーズ 2 はフェーズ 1 の完了後に実行してください。フェーズ 2 は偵察結果に依存します。
- フェーズ 3 は、フェーズ 2 のすべてのバッチが完了した後に実行してください。フェーズ 3 は、すべてのバッチ出力に依存します。
- バッチサイズはサブエージェント 1 つあたり候補 3 件です。候補が合計 1~3 件の場合は、サブエージェントを 1 つ使用します。候補が 10 件の場合は、サブエージェントを 4 つ使用します(3+3+3+1)。
- すべてのバッチサブエージェントを並行して起動してください。順次実行しないでください。
- 各バッチサブエージェントに渡すのは、偵察ファイル全体ではなく、割り当てられた候補のテキストだけです。これにより、各サブエージェントのコンテキストを小さく保ち、対象を絞れます。
- 重要な判断基準は、公開アクセス可能かどうかです。Django のビューにハードコードされた AWS キーは悪い慣行ですが、サーバー側にあるため、このスキルにおける検出対象ではありません。同じキーが React コンポーネントにある場合は、ブラウザーに配布されるため検出対象です。
- 判断に迷う場合は、インポートチェーンをたどってください。
src/utils/config.tsのようなファイルは、サーバー側とクライアント側の両方のコードからインポートされる場合があります。どのコードがインポートしているか確認してください。クライアント側のコードパスから 1 つでもインポートされていれば、シークレットは公開されています。 - モバイルアプリは常に公開扱いです。Android、iOS、React Native、Flutter、Xamarin アプリのすべてのソースコードは、抽出可能なものとして扱ってください。APK は
apktool/jadxで逆コンパイルでき、IPA は調査でき、React Native の JS バンドルは平文です。 - Firebase のクライアント設定は、一般にシークレットではありません。標準の Firebase クライアント設定(
apiKey、authDomain、projectIdなど)はクライアント側での使用を想定しており、Firebase Security Rules によって保護されています。検出対象とするのは、Firebase の管理者/サービスアカウントキーまたはサーバーキー(例:FIREBASE_ADMIN_SDK、private_keyを含むサービスアカウント JSON)のみです。 - Stripe の公開可能キーはシークレットではありません。
pk_live_*とpk_test_*はクライアント側での使用を想定しています。検出対象とするのはsk_live_*とsk_test_*(シークレットキー)のみです。 NEXT_PUBLIC_*、REACT_APP_*、VITE_*環境変数:これらはビルド時にクライアントバンドルに埋め込まれます。コードがprocess.env.NEXT_PUBLIC_API_KEYを参照している場合、クライアントからアクセス可能です。ただし、実際のハードコードされた値は通常 Git の追跡対象外である.envファイルにあります。環境変数から読み込んでいる場合ではなく、実際のシークレット値がソースコードにハードコードされている場合にのみ検出対象としてください。- 出力内のシークレットをマスキングしてください。コードスニペットを示す場合は、必ずシークレット値を一部マスキングしてください(例:
AKIA****WXYZ、sk_live_****abcd)。結果ファイルにシークレット値を完全な形で記載しないでください。 - 公開アクセス可能かどうか判断に迷う場合は、「脆弱性なし」ではなく「手動レビューが必要」に分類してください。セキュリティ評価では、誤検知より見逃しのほうが重大です。
- 中間ファイルをクリーンアップしてください。最終的な
sast/hardcodedsecrets-results.mdの書き込み後、sast/hardcodedsecrets-recon.mdとすべてのsast/hardcodedsecrets-batch-*.mdファイルを削除してください。