
コードベースをスキャンしてLLMのプロンプトインジェクションやマルチモーダルセキュリティの脆弱性を検出する静的解析ツールです。オフラインで動作し、APIコールは不要です。
ContextHoundは、開発・ブラウジングのワークフロー全体で利用可能です。
| ツール | 機能 | インストール方法 |
|---|---|---|
| CLI / npm パッケージ | コードベースをスキャンしてプロンプトインジェクションの脆弱性を検出。GitHub Actionsと統合し、SARIF、JSON、HTMLなどを出力。 | npm install -g context-hound |
| VS Code 拡張機能 | コーディング中のインラインファインディング、コードアクション、出力チャンネル、ステータスバー。 | VS Code Marketplace |
| ブラウザ拡張機能 | AIチャットインターフェース上のリアルタイムスキャンピル、LLM APIトラフィック用DevToolsパネル、ポップアップスキャナー。ChromeとFirefox対応。 | Firefox: 無料インストール · Chrome: 審査中 · ソース |
LLMを活用したアプリケーションがプロダクションコードベースで一般的になるにつれ、プロンプトインジェクションは最も悪用されやすい攻撃対象の一つとして浮上しています。しかし、ほとんどのセキュリティスキャナーはこれを認識していません。
ContextHoundは、プロンプトレイヤーに静的解析をもたらします。
既存のワークフローに、CLIコマンド、npmスクリプト、またはGitHub Actionとして適合し、外部依存関係はゼロです。
グローバルインストール — hound コマンドをPATHに追加:```bash
npm install -g context-hound
**プロジェクトごとのインストール** — 1つのリポジトリにスコープされ、`npx hound` または npmスクリプト経由で実行します:```bash
npm install --save-dev context-hound
Zero-install — インストール不要、キャッシュされたnpmレジストリのコピーを使用:```bash npx context-hound scan --dir .
## クイックスタート```bash
# Scaffold a config file
hound init
# Scan your project
hound scan --dir ./my-ai-project
# Or via npm script (scans current directory)
npm run hound
# Verbose output, shows remediations and confidence levels
hound scan --verbose
# Fail the build on any critical finding
hound scan --fail-on critical
# Export JSON and SARIF reports
hound scan --format console,json,sarif --out results
# GitHub Annotations (for CI step summaries)
hound scan --format github-annotations
# Markdown report with findings tables
hound scan --format markdown --out report
# Stream findings as JSONL (one JSON object per line)
hound scan --format jsonl | jq '.severity'
# List all rules
hound scan --list-rules
# Explain a rule (or a rule family by prefix)
hound explain INJ-001
hound explain PST --format json
# Fast PR gate — scan only files changed vs. origin/main
hound scan --diff
# Interactive HTML report (self-contained, open in browser)
hound scan --format html --out report
# Re-scan on file changes
hound scan --watch
# Parallel scanning (default is 8; tune for your machine)
hound scan --concurrency 16
# Disable incremental cache for a clean run
hound scan --no-cache
# Baseline mode — only report findings new since the last saved scan
hound scan --format json --out baseline # save a baseline
hound scan --baseline baseline.json # compare future scans against it
# Load a custom rule from a local plugin file
hound scan # plugin declared in .contexthoundrc.json "plugins" field
# Only run high-confidence rules
hound scan --config .contexthoundrc.json # set minConfidence: "high"
# Fail if any single file scores >= 40
hound scan --fail-file-threshold 40
終了コード:
| コード | 意味 |
|---|
ワークフローに追加して、プロンプトのリスクが高すぎる場合のマージをブロックします:```yaml
name: Prompt Audit
on: [push, pull_request]
jobs: hound: runs-on: ubuntu-latest permissions: contents: read security-events: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g context-hound
- run: hound scan --format console,sarif,github-annotations --out results.sarif
- name: Upload to GitHub Code Scanning
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
結果はリポジトリの **Security > Code scanning** タブに表示されます。`github-annotations` 形式は、PRにインラインコメントを投稿し、GitHubステップサマリーにサマリーテーブルを書き込みます。
---
## 設定
`hound init` を実行して `.contexthoundrc.json` をスキャフォールドするか、手動で作成します:```json
{
"include": ["**/*.ts", "**/*.js", "**/*.py", "**/*.go", "**/*.rs", "**/*.md", "**/*.txt", "**/*.yaml"],
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/tests/**",
"**/attacks/**"
],
"threshold": 60,
"formats": ["console", "sarif"],
"out": "results",
"verbose": false,
"failOn": "critical",
"maxFindings": 50,
"excludeRules": ["JBK-002"],
"includeRules": [],
"minConfidence": "medium",
"failFileThreshold": 80,
"concurrency": 8,
"cache": true,
"plugins": ["./rules/my-custom-rule.js"],
"baseline": "./baseline.json"
}
すべての主要設定は、設定ファイルを編集せずに実行時に上書きできます:
.houndignore.houndignore ファイルをプロジェクトルートに配置すると、.contexthoundrc.json を編集せずに除外パターンを追加できます。同じグロブ構文に従います。# で始まる行はコメントです。
ソース内で既知の誤検出を直接抑制します — リポジトリ全体でルールを無効にする必要はありません。ディレクティブは 任意の ファイルタイプで認識されます(周囲のコメント構文は関係ありません):```ts
// hound-disable-next-line INJ-001 -- userInput is a validated enum
const prompt = Summarise the ${userInput} report;
const cmd = run(${shell}); // hound-disable-line CMD-001
// hound-disable RAG-007 -- trusted internal corpus only context.push(doc.metadata.title); context.push(doc.metadata.author); // hound-enable RAG-007
- `hound-disable-line [RULE...]` — 同じ行の検出結果を抑制します
- `hound-disable-next-line [RULE...]` — 次の行の検出結果を抑制します
- `hound-disable [RULE...]` … `hound-enable [RULE...]` — ブロックを抑制します(ファイル末尾で自動的に閉じられます)
- ルールIDを省略すると、その場所で**すべての**ルールを抑制します;1つ以上(スペースまたはカンマ区切り)を指定すると、範囲を限定できます
- `--` 以降のテキストは自由形式の根拠説明で、レポートに表示されます
`--report-unused-suppressions` を付けて実行すると、どの検出結果にも一致しなくなったディレクティブをリスト表示し、不要になった抑制をクリーンアップできます。```bash
hound scan --report-unused-suppressions
IDを列挙する代わりに--presetを使用して、厳選されたルールのサブセットを有効にします。プリセットは既存のincludeRulesと結合され、複数のプリセットを組み合わせることができます:```bash
hound scan --preset owasp-llm-top10
hound scan --preset mcp,agentic
hound scan --list-presets # show all presets and their rule patterns
| プリセット | ルール |
|--------|-------|
| `owasp-llm-top10` | INJ, JBK, EXF, OUT, RAG, TOOL, SCH, DOS, VIS |
| `injection` | INJ, RAG, ENC |
| `jailbreak` | JBK |
| `exfiltration` | EXF |
| `agentic` | AGT, MCP, TOOL |
| `mcp` | MCP |
| `supply-chain` | SCH |
| `prompt-files` | INJ, JBK, EXF, ENC, SKL |
### pre-commit フック
ContextHound には [pre-commit](https://pre-commit.com) フックが同梱されています。次の行を `.pre-commit-config.yaml` に追加してください:```yaml
repos:
- repo: https://github.com/IulianVOStrut/ContextHound
rev: v2.0.0
hooks:
- id: contexthound
# optional — scan only changed files and fail on high-severity findings:
# args: ["--diff", "HEAD", "--fail-on", "high"]
Rule または Rule[] をエクスポートする .js ファイルは、プラグインとしてロードできます:```js
// my-rule.js
module.exports = {
id: 'CUSTOM-001',
title: 'Proprietary data pattern in prompt',
severity: 'high',
confidence: 'high',
category: 'injection',
remediation: 'Remove internal identifiers from prompts.',
check(prompt) {
if (prompt.text.includes('INTERNAL_PATTERN')) {
return [{ evidence: 'INTERNAL_PATTERN', lineStart: 1, lineEnd: 1 }];
}
return [];
},
};
`.contexthoundrc.json` でそれを参照してください:```json
{ "plugins": ["./my-rule.js"] }
プラグインルールは、組み込みルールと同じexcludeRules、includeRules、minConfidenceフィルターの対象となります。
初期スキャン後にベースラインを保存し、その後のスキャンで新しい発見のみを報告します。```bash
hound scan --format json --out baseline
hound scan --baseline baseline.json
検出結果は `ruleId + file` で照合されます — 行の移動によって新たな誤検出警告が発生することはありません。
### Changed-files-only (`--diff`)
高速なプルリクエストゲートのために、ツリー全体ではなく、gitリファレンスに対して変更されたファイルのみをスキャンします:```bash
hound scan --diff # vs. origin/main (default)
hound scan --diff main # vs. a named branch
hound scan --diff HEAD~5 # vs. an arbitrary ref
コミット済み、ステージング済み、未ステージング、そして無視されていないが追跡されていないファイルを対象とします。gitが利用できない場合や、refが解決できない場合(例:浅いCIクローン)、ContextHoundは警告を表示し、静かに通過するのではなく、完全スキャンにフォールバックします。--baselineと組み合わせてfindingsレベルの差分を取得するか、--diffのみを使用して最速のPRフィードバックを得ることができます。
各発見事項には、以下のように計算されるリスクポイントが付与されます:``` risk_points = severity_weight × confidence_multiplier
Points are totalled, capped at 100, and classified:
| スコア | レベル | 推奨アクション |
|-------|-------|-----------------|
| 0-29 | 🟢 低 | アクション不要 |
| 30-59 | 🟡 中 | マージ前に確認 |
| 60-79 | 🟠 高 | マージ前に修正 |
| 80-100 | 🔴 重大 | デプロイをブロック |
プロンプトに明示的な安全文言(入力デリミタ、非開示指示、ツール許可リスト)が含まれている場合、そのプロンプトのリスクポイントは比例して減少します。
---
## ルール
### A. インジェクション (INJ)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| INJ-001 | 高 | デリミタなしでプロンプトに直接連結されたユーザー入力 |
| INJ-002 | 中 | 「ユーザーコンテンツをデータとして扱う」境界文言の欠如 |
| INJ-003 | 高 | 信頼できないセパレータなしでRAG/検索コンテキストが含まれている |
| INJ-004 | 高 | ツール使用指示がユーザーコンテンツで上書き可能 |
| INJ-005 | 高 | シリアライズされたユーザーオブジェクト(`JSON.stringify`)がプロンプトテンプレートに直接挿入されている |
| INJ-006 | 中 | ユーザー制御コンテンツ内の隠された指示動詞を含むHTMLコメント |
| INJ-007 | 中 | バッククォートを最初に除去せずにコードフェンスデリミタで囲まれたユーザー入力 |
| INJ-008 | 高 | HTTPリクエストデータ(`req.body`、`req.query`、`req.params`)が`role: "system"`テンプレート文字列に挿入されている |
| INJ-009 | 重大 | HTTPリクエストボディが直接メッセージ配列としてパースされる — 攻撃者がロールとコンテンツを制御 |
| INJ-010 | 高 | プレーンテキストのロールラベル転記(`User:`、`Assistant:`、`system:`)が信頼できない入力の連結で構築されている |
| INJ-011 | 高 | ブラウザのDOMまたはURLソース(`window.location`、`document.cookie`、`getElementById`)がLLM呼び出しに直接渡されている |
| INJ-012 | 高 | 会話履歴がサニタイズなしでメッセージ配列に展開されている |
| INJ-013 | 高 | ツール/関数呼び出し結果がサニタイズなしでメッセージに挿入されている |
| INJ-014 | 高 | LLM完了がユーザーロールコンテンツとして後続のLLM呼び出しにパイプされている |
| INJ-015 | 高 | 信頼できない外部入力(HTTP/CLI/DOM)がプロンプトに流れ込む — 名前非依存の**汚染解析**、エイリアスを追跡、サニタイザを尊重 |
### B. 流出 (EXF)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| EXF-001 | 重大 | プロンプトが秘密、APIキー、または認証情報を参照している |
| EXF-002 | 重大 | プロンプトがモデルにシステムプロンプトや隠し指示を開示するよう指示している |
| EXF-003 | 高 | プロンプトが機密データやプライベートデータへのアクセスを示している |
| EXF-004 | 高 | プロンプトに内部URLやインフラストラクチャのホスト名が含まれている |
| EXF-005 | 高 | 機密変数(トークン、パスワード、キー)が出力でBase64エンコードされている |
| EXF-006 | 高 | 完全なプロンプトまたはメッセージ配列が`console.log`/`logger.*`でマスキングなしでログ記録されている |
| EXF-007 | 重大 | 実際の秘密の値が「絶対に明かさない」指示とともにプロンプトに埋め込まれている |
### C. 脱獄 (JBK)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| JBK-001 | 重大 | 既知の脱獄フレーズが検出された("ignore instructions"、"DAN"など) |
| JBK-002 | 高 | 弱い安全文言("always comply"、"no matter what") |
| JBK-003 | 高 | 安全制約を弱体化させるロールプレイ脱出ハッチ |
| JBK-004 | 高 | エージェントが確認や人間のレビューなしで行動するよう指示されている("proceed automatically"、"no confirmation needed") |
| JBK-005 | 高 | 証拠消去または痕跡隠蔽の指示("delete logs"、"leave no trace") |
| JBK-006 | 高 | ポリシーの正当性の枠組みと安全でないアクション要求の組み合わせ("as a penetration tester, escalate privileges") |
| JBK-007 | 高 | モデルIDのなりすまし — 異なるAIモデルを主張し、安全バイパス指示と組み合わせる |
| JBK-008 | 高 | プロンプト圧縮攻撃 — システムプロンプトを圧縮または要約する指示 |
| JBK-009 | 高 | ネストされた指示インジェクション — "安全/無害な要約/翻訳"の枠組みに包まれた命令型コマンド |
### D. 安全でないツール使用 (TOOL)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| TOOL-001 | 重大 | 制限のないツール実行("run any command"、"browse anywhere"、バッククォートシェル置換) |
| TOOL-002 | 中 | 許可リストや使用ポリシーなしでツール使用が記述されている |
| TOOL-003 | 高 | サンドボックス制約なしでコード実行が言及されている |
| TOOL-004 | 重大 | ツールの説明やスキーマフィールドがユーザー制御変数から取得されている |
| TOOL-005 | 重大 | ツールの`name`またはエンドポイント`url`がユーザー制御入力(`req.body`、`req.query`など)から取得されている |
### E. コマンドインジェクション (CMD)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| CMD-001 | 重大 | サニタイズされていない変数補間でシェルコマンドが構築されている — JS/TS(`execSync(\`cmd ${var}\``)、Python(`subprocess.run(f"cmd {var}")`)、PHP(`shell_exec($var)`)、Go(`exec.Command` + `fmt.Sprintf`)、Rust(`Command::new` + `format!`) |
| CMD-002 | 高 | 不完全なコマンド置換フィルタリング:`$()`をブロックするがバッククォートをブロックしない、またはその逆 |
| CMD-003 | 高 | `glob.sync`や`readdirSync`からのファイルパスがサニタイズなしで直接シェルコマンドで使用されている |
| CMD-004 | 重大 | Pythonの`subprocess.run`/`subprocess.call`が`shell=True`と変数またはf-stringコマンド引数で呼び出されている |
| CMD-005 | 重大 | PHPの`shell_exec`、`system`、`passthru`、`exec`、または`popen`が`$variable`引数で呼び出されている |
### F. RAGポイズニング (RAG)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| RAG-001 | 高 | 取得または外部コンテンツがメッセージ配列内で`role: "system"`に割り当てられている |
| RAG-002 | 高 | 指示のようなフレーズ("system prompt:"、"always return"、"never redact")がドキュメント取り込みループ内で検出された |
| RAG-003 | 高 | エージェントメモリストアが検証なしでユーザー制御入力から直接書き込まれている |
| RAG-004 | 中 | プロンプトがモデルに取得コンテキストを最優先として扱うよう指示し、開発者の指示を上書きしている |
| RAG-005 | 中 | 出所なしの取得 — ソースメタデータチェックなしでチャンクがプロンプトに挿入されている |
| RAG-006 | 高 | 取得がプロンプトに入る前にACLまたは信頼ティアフィルタが適用されていない |
### G. エンコーディング (ENC)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| ENC-001 | 中 | プロンプト構築の近くでユーザー制御変数に対して`atob`、`btoa`、または`Buffer.from(x, 'base64')`が呼び出されている |
| ENC-002 | 高 | 指示キーワードの近くで隠されたUnicode制御文字(ゼロ幅スペース、双方向オーバーライド)が検出された |
### H. 出力処理 (OUT)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| OUT-001 | 重大 | スキーマ検証(Zod、AJV、Joi、Pydantic、Marshmallowなど)なしでLLM出力に対して`JSON.parse()`(JS/TS)または`json.loads()`(Python)が呼び出されている |
| OUT-002 | 重大 | DOMPurifyまたは同等のサニタイザなしでLLM生成のMarkdownまたはHTMLがレンダリングされている |
| OUT-003 | 重大 | LLM出力が`exec()`、`eval()`、または`db.query()`の引数として直接使用されている |
| OUT-004 | 重大 | LLM生成の出力を引数としてPythonの`eval()`または`exec()`が呼び出されている |
### I. マルチモーダル (VIS)
| ID | 重大度 | 説明 |
|----|----------|-------------|
| VIS-001 | 重大 | ドメインまたはMIME検証なしで、ユーザー提供の画像URLまたはbase64データがビジョンAPI(gpt-4o、Claude 3、Gemini Vision)に転送されている |
| VIS-002 | 重大 | ビジョンAPIメッセージも構築するファイル内で、ユーザー制御パスで`fs.readFile`/`readFileSync`が呼び出されている — マルチモーダル入力へのパストラバーサル |
| VIS-003 | 高 | サニタイズなしで音声/動画文字起こし出力(Whisper、AssemblyAI、Deepgramなど)が直接プロンプトメッセージに渡されている — 音声ソース経由のRAGポイズニング |
| VIS-004 | 高 | OCR出力(Tesseract、Google Vision)が`role: "system"`メッセージまたはシステムプロンプト変数に挿入されている |
### J. スキルマーケットプレイス (SKL) — v1.1
| ID | 重大度 | 説明 |
|----|----------|-------------|
| SKL-001 | 重大 | スキル本文がエージェントに他のスキルファイルの書き込みまたは変更を指示する — エージェント再起動後も持続する自己作成攻撃 |
| SKL-002 | 重大 | スキル本文がエージェントに外部URLからスキルを取得またはロードするよう指示する — インストール後に攻撃者がスキルの動作を変更できる |
| SKL-003 | 重大 | スキル本文にエージェントのコア指示を標的としたプロンプトインジェクションフレーズが含まれている(`ignore previous instructions`、`you are now unrestricted`など) |
| SKL-004 | 高 | スキルのフロントマターが`command-dispatch: tool`と`command-arg-mode: raw`を使用している — 生のユーザー入力をツールに転送し、モデルの安全推論をバイパスする |
| SKL-005 | 高 | スキル本文が機密ファイルシステムパス(`~/.ssh`、`~/.env`、`/etc/passwd`、`../../`)を参照し、エージェントが読み取り、潜在的に流出させる |
| SKL-006 | 高 | スキル本文が昇格された権限を主張するか、エージェントに他のインストール済みスキルを上書きまたは無効化するよう指示する |
| SKL-007 | 重大 | YAMLフロントマターにハードコードされた認証情報(APIキー、トークン、パスワード)が見つかった — スキルを受け取った人やインストールした人に公開される |
| SKL-008 | 重大 | Heartbeat C2 — スキルが定期的なリモートフェッチをスケジュールし、クリーンインストール後に自身の指示を静かに上書きする |
| SKL-009 | 重大 | エージェントIDの否定 — スキルがエージェントにAIであることを否定し、人間であると主張するか、欺瞞的なペルソナを採用するよう指示する |
| SKL-010 | 重大 | スキャナー回避 — スキルにセキュリティ監査ツールを誤解させるために明示的に設計されたテキストが含まれている |
| SKL-011 | 重大 | SOUL.md / IDENTITY.mdの永続性 — スキルがアンインストール後も残るエージェントIDファイルに指示を書き込む |
| SKL-012 | 高 | 自己増殖ワーム — スキルがエージェントに到達可能なホストへSSHまたは`curl\|bash`で拡散するよう指示する |
| SKL-013 | 高 | 自律的な金融取引 — スキルが1取引ごとのユーザー確認なしで暗号取引を実行するか、秘密鍵を保持する |
> **OpenClawスキルのスキャン:** `npx hound scan --dir ./skills` を実行するか、`**/skills/**/*.md` と `**/SKILL.md` を `include` 設定に追加してください。ContextHoundは自動的にスキルファイルを複数行ルール解析用の `code-block` として出力します。
### K. エージェンティック (AGT) — v1.3 / v1.9
| ID | 重大度 | 説明 |
|----|----------|-------------|
| AGT-001 | 重大 | ツール呼び出しパラメータがシステムプロンプトコンテンツを受け取る — `tool_call`/`function_call`引数値に`system:`または`instructions:`フィールドの内容が含まれている |
| AGT-002 | 高 | 反復またはタイムアウトガードのないエージェントループ — エージェント設定またはコードに`max_iterations`、`max_steps`、`max_turns`、`timeout`、または`recursion_limit`がない |
| AGT-003 | 高 | 未検証のLLM出力からエージェントメモリが書き込まれている — `memory.save()`、`memory.add()`、または`vectorstore.upsert()`が生のモデル応答変数で呼び出されている |
| AGT-004 | 高 | プランインジェクション — ユーザー入力が信頼境界ラッパーなしで直接エージェントの計画、タスク、または目標プロンプトに挿入されている |
| AGT-005 | 重大 | 暗号検証なしでエージェントが主張されたIDを信頼する — HMAC、JWT、または共有秘密検証なしで`agentId`、`sender`、`source`、または`from_agent`フィールドに基づいて信頼判断が行われる |
| AGT-006 | 高 | 検証なしで生のエージェント出力が別のエージェントへの入力として連鎖している — 別のエージェントの`.output`/`.content`/`.result`を直接引数として`.run()`、`.invoke()`、または`.generate()`が呼び出されている |
| AGT-007 | 重大 | エージェントの自己変更 — エージェントが実行時にLLM生成コンテンツで自身の`system_prompt`、`instructions`、または`tools`リストを書き換える |
| AGT-008 | 重大 | ASI03 — エージェントがLLM出力から派生した値で`assumeRole`、`grantAccess`、または`setPermissions`を呼び出す; プロンプトインジェクションによる権限昇格 |
| AGT-009 | 高 | ASI04 — エージェントが変数パスまたは動的インポートから実行時にツールまたはプラグインをロードし、サプライチェーン置換を可能にする |
| AGT-010 | 高 | ASI07 — HMAC、JWT署名、またはスキーマ検証なしで`send`/`route`/`dispatch`を介して生のエージェント出力が別のエージェントに転送される |
| AGT-011 | 高 | ASI08 — エージェントプランステップのエラーが静かにキャッチされる(再スローなし、エラー状態フラグなし); 後続のステップが不良または不完全な状態で続行される |
### L. MCPセキュリティ (MCP) — v1.7 / v1.8
| ID | 重大度 | 説明 |
|----|----------|-------------|
| MCP-001 | 重大 | サニタイゼーションなしでMCPツール説明がLLMプロンプトに注入されている — 生の `tool.description` 値が `role: "system"` または `messages.push()` で使用されている |
| MCP-002 | 高 | 動的な名前または説明でMCPツールが登録されている — `server.tool()` の最初の引数が変数またはテンプレートリテラルであり、承認後の改ざん攻撃を可能にする |
| MCP-003 | 高 | 人間の承認ガードなしのMCP sampling/createMessageハンドラ — `requireHumanApproval`、`confirm`、または `approve` チェックなしの `setRequestHandler(CreateMessageRequestSchema)` |
| MCP-004 | 中 | 変数から構築されたMCPトランスポートURL — `SSEClientTransport` または `WebSocketClientTransport` が静的文字列ではなく `new URL(variable)` で初期化されている |
| MCP-005 | 高 | MCP stdioトランスポートが `shell: true` を使用している — コマンド文字列がシェル補間され、引数がユーザー制御の場合にインジェクション可能になる |
| MCP-006 | 重大 | MCP混乱した代理人 — MCPリクエストからの認証トークンが再検証なしで下流APIに転送される; `Authorization` ヘッダー値が `request.params`、`context`、または `event` から直接取得される |
| MCP-007 | 高 | クロスMCPコンテキストポイズニング — ハッシュ、署名、または出所チェックなしでMCP出力から共有/グローバルコンテキストストアに書き込まれる |
| MCP-008 | 高 | 変数パスからロードされたMCP stdioトランスポートコマンド — `StdioClientTransport`/`StdioServerTransport` の `command:` フィールドが静的リテラルではなく変数である |
| MCP-009 | 高 | 有効期限チェックなしでMCPセッションIDが認証判断に使用されている — TTL、`expiresAt`、または `isExpired` ガードなしの `sessionId`/`connectionId` 等価比較(リプレイ攻撃) |
| MCP-010 | 重大 | サニタイゼーションなしでMCPトランスポートイベントペイロードがLLMコンテキストに注入されている — イベント/メッセージの`.data`、`.content`、または `.payload` が `messages.push()` または `content:` フィールドで直接使用されている |```
=== ContextHound Prompt Audit ===
src/prompts/assistant.ts (file score: 73)
[HIGH] INJ-001: Direct user input concatenation without delimiter
File: src/prompts/assistant.ts:12
Evidence: Answer the user's question: ${userInput}
Confidence: medium
Risk points: 23
Remediation: Wrap user input with clear delimiters (e.g., triple backticks)
and label it as "untrusted user content".
[CRITICAL] EXF-001: Prompt references secrets, API keys, or credentials
File: src/prompts/assistant.ts:8
Evidence: The database password is: secret123.
Confidence: high
Risk points: 50
Remediation: Remove all secret values from prompts. Use environment
variables server-side; never embed credentials in prompt text.
────────────────────────────────────────────────────────
Repo Risk Score: 87/100 (CRITICAL)
Threshold: 60
Total findings: 5
By severity: critical: 2 high: 2 medium: 1
✗ FAILED - score meets or exceeds threshold.
src/ ├── cli.ts # CLI entry point (Commander.js) ├── types.ts # Shared TypeScript types ├── config/ │ ├── defaults.ts # Default include/exclude globs and settings │ └── loader.ts # .contexthoundrc.json loader + env var overrides ├── scanner/ │ ├── discover.ts # File discovery via fast-glob │ ├── extractor.ts # Prompt extraction (raw, code, structured) │ ├── languages.ts # LLM API trigger patterns per language extension │ ├── cache.ts # Incremental scan cache (.hound-cache.json) │ └── pipeline.ts # Orchestrates the full scan; parallel + cache + plugins ├── rules/ │ ├── types.ts # Rule interface and scoring helpers │ ├── injection.ts # INJ-* rules │ ├── exfiltration.ts # EXF-* rules │ ├── jailbreak.ts # JBK-* rules │ ├── unsafeTools.ts # TOOL-* rules │ ├── commandInjection.ts # CMD-* rules │ ├── rag.ts # RAG-* rules │ ├── encoding.ts # ENC-* rules │ ├── outputHandling.ts # OUT-* rules │ ├── multimodal.ts # VIS-* rules │ ├── skills.ts # SKL-* rules │ ├── agentic.ts # AGT-* rules │ ├── mcp.ts # MCP-* rules │ ├── supplyChain.ts # SCH-* rules │ ├── dos.ts # DOS-* rules │ ├── mitigation.ts # Mitigation presence detection │ └── index.ts # Rule registry ├── runtime/ │ ├── index.ts # createGuard() — runtime message inspection API │ ├── inspect.ts # Core inspection logic for live message arrays │ └── types.ts # RuntimeMessage, InspectResult, GuardConfig types ├── scoring/ │ └── index.ts # Risk score calculation and rule filtering └── report/ ├── console.ts # ANSI-coloured terminal output ├── json.ts # JSON report builder ├── sarif.ts # SARIF 2.1.0 report builder ├── githubAnnotations.ts# GitHub Actions annotation formatter ├── markdown.ts # Markdown report with findings tables ├── jsonl.ts # JSONL streaming formatter └── html.ts # Self-contained interactive HTML report attacks/ # Example injection strings (not executed against models) tests/ ├── fixtures/ # Sample prompts for testing ├── rules.test.ts # Unit tests for all rules ├── scoring.test.ts # Unit tests for scoring logic ├── scanner.test.ts # Integration tests for the scan pipeline ├── extractor.test.ts # Unit tests for prompt extraction ├── formatters.test.ts # Unit tests for all report formatters ├── mitigation.test.ts # Unit tests for mitigation detection └── cli.test.ts # CLI integration tests (init, list-rules, exit codes) .github/ ├── action.yml # Reusable composite GitHub Action └── workflows/ └── context-hound.yml # CI workflow
---
## Benchmark
ContextHoundには、偽陽性率と検出率を測定するためのラベル付きベンチマークデータセットが同梱されています。ビルド後に実行してください。```bash
npm run benchmark
ベンチマークは2つのフィクスチャディレクトリをスキャンします:
| ディレクトリ | 目的 |
|---|---|
benchmarks/safe/ | 実際の安全なパターンを含む5ファイル — 0件の検出を期待 |
benchmarks/unsafe/ | 実際の脆弱性を含む8ファイル — ルールごとに1件 |
v1.4.0 での結果:``` File-level FP rate: 0.0% (0 / 5 safe files produced findings) Detection rate: 100.0% (8/8 expected findings triggered)
ベンチマークは、誤検知または見逃しが見つかった場合、コード1で終了するため、ルール変更のCI品質ゲートとして適しています。フィクスチャを追加するには、`benchmarks/safe/` または `benchmarks/unsafe/` にファイルを配置し、期待される検出結果を `benchmarks/labels.json` に更新します。
### ルールごとの適合率 / 再現率
ベンチマークはまた、**ルールごとのシグナル表**(F1値が低い順)を出力するため、適合率の低いルールがすぐに特定できます。各ラベル付きルールについて、真陽性/偽陽性、偽陰性、適合率、再現率、F1値を表示します。FP数は `safe/` フィクスチャ(正解データ:検出結果ゼロ)から取得され、TP/FNはラベル付き `unsafe/` フィクスチャから取得されます。`--report <path>` を指定すると、ダッシュボードやCIトレンド追跡用の機械可読なJSONレポートも出力されます。```bash
npm run benchmark -- --report bench-report.json
ContextHound ブラウザ拡張機能は、Chrome と Firefox でリアルタイムのプロンプトインジェクション検出を実現します。CLI と同じルールエンジンを使用し、ローカルでコンパイル・バンドルされています。ネットワークリクエストやバックエンドは必要ありません。
ステータス: Firefox 拡張機能は公開中 — Firefox Add-ons からインストール。Chrome の申請は Web Store の審査待ちです。ソースコードは github.com/IulianVOStrut/ContextHound-Extensions で入手できます。
スキャンピル 任意のウェブサイト上の AI チャット入力欄の横に、軽量なインジケーターが表示されます。入力中、拡張機能は 70 の検出ルールに基づいてテキストをスキャンし、リスクスコアと検出結果をドロップダウンパネルに表示します。ページ遷移は不要です。
DevTools パネル ブラウザの DevTools を開き、ContextHound タブを選択すると、ライブの LLM API トラフィックを監視できます。拡張機能は OpenAI、Anthropic、Google Gemini、Mistral、Groq、Cohere、DeepSeek などのサービスへのアウトバウンドリクエストをインターセプトし、リクエストボディとレスポンスの両方をインジェクションコンテンツについてスキャンします。ツールバーバッジには、現在のセッションで確認された最高リスクスコアが表示されます。
ポップアップスキャナー ツールバーアイコンをクリックすると、任意のテキストを貼り付けて手動でスキャンできます。第三者から受け取ったプロンプトやシステム指示を、使用前に確認するのに便利です。
Chrome と Firefox の DevTools HAR API(onRequestFinished)は、ほとんどの AI チャットサービスが使用するストリーミング/SSE レスポンスの場合、リクエストボディのバイトを確実に含みません。拡張機能は、次の 2 層アプローチでこの問題を解決しています。
chrome.webRequest.onBeforeRequest が、リクエストが送信される前にサービスワーカー内で生のリクエストバイトをインターセプトし、chrome.storage.session(TTL: 5 分)に一時的にキャッシュします。onRequestFinished が発火し、postData が欠落している場合、DevTools ページは POP_BODY_CACHE メッセージを介してサービスワーカーからキャッシュされたボディを取得します。拡張機能はユーザーデータを一切収集しません。すべてのスキャンはローカルで行われます。プライバシーポリシー をご覧ください。
貢献を歓迎します。新しいルールを追加するには:
src/rules/ 内の適切なファイルに追加します(新しいカテゴリの場合は新しいファイルを作成します)src/rules/index.ts に登録しますtests/rules.test.ts に少なくとも 1 つの正常系テストと 1 つの異常系テストを追加しますnpm test を実行してすべてのテストが合格することを確認しますMIT
| 95のセキュリティルール | 14カテゴリにわたる:インジェクション、不正送信、脱獄、安全でないツール使用、コマンドインジェクション、RAGポイズニング、エンコーディング、出力処理、マルチモーダル、スキルマーケットプレイス、エージェント、MCP、サプライチェーン、DoS |
| 数値リスクスコア(0-100) | リポジトリレベルの正規化スコア(低・中・高・重大のしきい値あり) |
| 緩和策の検出 | プロンプト内の明示的な安全な表現によりスコアが低下 |
| 7つの出力形式 | コンソール、JSON、SARIF、GitHub Annotations、Markdown、JSONLストリーミング、インタラクティブHTML |
| GitHub Action内蔵 | 高リスク時にCIを失敗させ、SARIF結果を自動アップロード |
| 多言語スキャン | Python、Go、Rust、Java、C#、PHP、Ruby、Swift、Kotlin、Vue、BashでのLLM API使用を検出(TypeScript/JavaScriptだけでない) |
| ルールフィルタリング | excludeRules/includeRules(プレフィックスグロブ構文 CMD-*); minConfidenceフィルター |
| インクリメンタルキャッシュ | .hound-cache.json で再実行時に変更のないファイルをスキップ; --no-cache で無効化 |
| プラグインシステム | 設定ファイルの "plugins": ["./my-rule.js"] により、ローカルの .js ファイルからカスタムルールを読み込み |
| ベースライン / 差分モード | --baseline results.json — 以前のスキャンに存在しないファインディングのみ報告・失敗 |
| ウォッチモード | --watch でファイル変更時に再スキャンし、差分ファインディングを表示 |
| 並列スキャン | 同時ファイル処理(--concurrency <n>、デフォルト8) |
| 完全オフライン | APIコールなし、テレメトリーなし、有料依存関係なし |
0 | 合格 — スコアがしきい値を下回り、failOn違反なし |
1 | 未処理のエラーまたは不正な引数 |
2 | しきい値違反 — リポジトリのスコアがしきい値以上、またはファイルのしきい値を超過 |
3 | --fail-on違反 — 指定された重要度の検出があった |
| オプション | デフォルト | 説明 |
|---|
include | **/*.{ts,tsx,js,jsx,py,go,rs,java,kt,cs,php,rb,swift,vue,sh,bash,hs,md,txt,yaml,yml,json} | スキャンするグロブパターン |
exclude | **/node_modules/**, **/dist/** など | 無視するグロブパターン |
threshold | 60 | リポジトリスコアがこの値以上の場合に失敗(終了コード2) |
formats | ["console"] | 出力形式:console, json, sarif, github-annotations, markdown, jsonl, html |
out | 自動 | ファイル出力のベースパス |
verbose | false | 検出ごとの修復と信頼度を表示 |
failOn | 未設定 | 最初に見つかった重要度が critical, high, medium の場合に終了コード3を返す |
maxFindings | 未設定 | N件の検出後に停止 |
excludeRules | [] | スキップするルールIDまたは接頭辞グロブ(例:"CMD-*", "JBK-002") |
includeRules | [] | これらのルールIDのみを実行(空の場合はすべて実行) |
minConfidence | 未設定 | この信頼度未満のルールをスキップ:low, medium, high |
failFileThreshold | 未設定 | いずれかの単一ファイルのスコアがこの値以上の場合に失敗(終了コード2) |
concurrency | 8 | 並列処理される最大ファイル数 |
cache | true | インクリメンタルスキャンキャッシュを有効にする(.hound-cache.json);無効にするには false または --no-cache を設定 |
plugins | [] | ローカルの .js ルールプラグインへのパス;各プラグインは Rule または Rule[] をエクスポートする必要がある |
baseline | 未設定 | 以前のJSONレポートへのパス;ベースラインに存在しない検出のみが報告される |
| 変数 | 上書き対象 |
|---|
HOUND_THRESHOLD | threshold |
HOUND_FAIL_ON | failOn |
HOUND_MIN_CONFIDENCE | minConfidence |
HOUND_VERBOSE | verbose(真偽値:1, true, yes) |
HOUND_CONFIG | 設定ファイルへのパス |