
SecureAI-Scan v0.7.0
SecureAI-Scan は、TypeScript および JavaScript のコードベースをスキャンして、AI を活用したアプリに固有のセキュリティ問題(プロンプトインジェクション、MCP ツールの悪用、RAG データポイズニング、エージェントの信頼違反など)を検出する CLI ツールです。
SecureAI-Scan
検出結果を証明するAIセキュリティスキャナ。
SecureAI-Scan は、TypeScript、JavaScript、Python における LLM、MCP、Agent Skill、RAG の脆弱性を検出し、その証拠を提示します。すべてのデータフロー検出結果について、実際のインポートを解決して特定した正確な source → flow → sink パスを表示します(キーワードマッチングではありません)。
これは、公式の OWASP Top 10 for LLM Applications 2026 に加え、Top 10 for Agentic Applications (2026) と MCP Top 10 に対してローンチウィークでサポートを提供します。各脅威モデルは、静的カバレッジとランタイムの考慮事項を区別します。
30秒で始める```bash
npx --yes [email protected] scan .
アカウント、クラウドアップロード、Pythonインタープリター、設定は一切不要です。TypeScript、JavaScript、Python、MCP構成、Agent Skillバンドルは自動的に検出されます。
**計測済み `0.9.0` リリース候補:** 136/136のテスト · 88.08%のステートメントカバレッジ · 9つの公開リポジトリにわたる12,676ファイル · レビュー済みベースラインに対するデフォルトティアの新規フィンガープリント0件。 [エビデンス](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/benchmarks/v0.9.0.json) · [方法論と制限](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/ReleaseAssurance.md)```
▌ HIGH AI001 Prompt injection via user input
PROVEN LLM01:2026 Prompt Injection
source src/chat.ts:8 request data `req.body.input`
flow src/chat.ts:13 passed as `systemPrompt`
sink src/chat.ts:10 openai.chat.completions.create — system role (OpenAI)
fix Keep system prompts static; pass user input as a user-role message.
これはあなた向けですか? SecureAI-Scan は、LLM・MCP・RAG/エージェントのリスク(プロンプトインジェクション、ツールポイズニング、安全でない出力処理、ベクターストアのアクセス制御、エージェントスキルのポイズニング)に意図的に範囲を絞っています。一般的な SAST やシークレットスキャナーではなく、そのような万能ツールを目指していません。LLM 型のペイロードを持たない既知の悪意あるパッケージ(例: メール API 呼び出しにハードコードされた外部送信アドレス)は、パターンルールではなくオフラインのアドバイザリリスト(DEP003)で検出されます。あなたのコードベースが LLM、MCP サーバー、ベクターストアと通信する場合、または Agent Skills を出荷する場合、このツールはあなたのために作られています。
目次
- このスキャナーが他と違う理由
- 他ツールとの比較
- 30秒で始める
- 動作の確認
- コマンド
- GitHub Action
- ルール
- アーキテクチャ
- MCPサーバー(Claudeから使用)
- Claude スキル
- 信頼性とリリース保証
- 精度に関する契約
- テストとベンチマーク
- ロードマップ
- コントリビューション
このスキャナーが他と違う理由
- 証拠レベルによる分類、ノイズではない。 すべての検出結果は、
proven(トレースされたデータフローまたは解析済み設定の事実)、likely(解決されたシンク、ヒューリスティックなホップ1回)、またはheuristicのいずれかです。デフォルトスキャンではprovenとlikelyのみ表示されます。 ヒューリスティックは--paranoidでオプトインできます。 - インポート解決による検出。 実際の SDK インポート(
openai、@anthropic-ai/sdk、ai、@google/genai、LangChain、Bedrock、…)に解決される場合のみ、呼び出しを「LLM 呼び出し」とみなします。Google Maps クライアントが再び LLM としてフラグ付けされることはありません。 - 精度ゲート付きで、実リポジトリに対してベンチマーク済み。 テストスイートは、すべての脆弱フィクスチャが検出されること かつ すべての安全なフィクスチャがクリーンのままであることを検証します。安全なコーパスでの誤検知はビルドを失敗させます。さらに、
npm run regressionは実際の公開リポジトリ(OpenAI/Anthropic/Vercel AI SDK、公式 MCP サーバー、LlamaIndex)を、コミット済みの手動レビュー済みベースラインと比較してスキャンし、新しいproven/likely検出があれば失敗します。実際の前後数値は テストとベンチマーク を参照し、その背景にあるストーリーは 実リポジトリのスキャンで見つかったもの を参照してください。ラベル付きの悪意あるスキルコーパスでの 6/6 キャッチ率と、正当なライブラリレベルの検出結果をもって llama_index を「脆弱」と 呼んでいない 理由もそこにあります。 - GitHub コードスキャン向け SARIF。
--output report.sarifにより、検出結果がプルリクエストと Security タブにインライン表示されます。 - AI-BOM(AI 部品表)。
secureai-scan bom .は、SDK、モデル ID、ベクターストア、エージェントフレームワーク、MCP サーバーの構文解析由来インベントリを構築し、OWASP LLM Top 10 / EU AI Act のドキュメント要件に対応付けます。 - MCP 設定スキャン。
.mcp.json、claude_desktop_config.json、.cursor/mcp.jsonを解析します: バージョン固定されていないnpx -yサーバー、インラインシークレット、平文 HTTP トランスポートを検出。 - MCP ツールポイズニング検出。 WhatsApp MCP の rug-pull と postmark-mcp バックドアの背後にあるパターン、つまり不可視 Unicode、エージェント向けインジェクション文、ツール名/説明におけるツール間シャドウイングを、サーバーを実行する前に静的解析で検出します。
- MCP コマンドインジェクション検出。 リクエストデータから構築された MCP stdio トランスポートの
command/argsをフラグ付けします。これは 2026 年の MCP STDIO RCE 開示の背後にあるパターンです。 - Agent Skill ポイズニング検出。 同じ不可視 Unicode、インジェクション文、シャドウイングのチェックを
SKILL.mdファイルに適用します。Agent Skills はコンテキストに丸ごと読み込まれるため、ポイズニングされたスキルは名前を変えたポイズニングされたツールの説明に他なりません。 - 回避耐性のあるスキルスキャン。 スキルバンドルは
SKILL.mdだけでなく ディレクトリ としてスキャンされ、すべてのコンテンツチェックはテキストの難読化解除(deobfuscated)バリアントに対して実行されます。これは公開されている手法、つまりホモグリフ、ゼロ幅分割、.git/やbuild/にステージングされたペイロード、*.test.tsファイルに隠された外部送信を対象にしており、Cloak and Detonate(arXiv:2607.02357)で調査された9つのスキャナーの 90%以上 をすり抜けたものです。回避耐性 を参照してください。 - 既知脆弱・既知悪意パッケージのバージョン認識型アドバイザリ。 すべての依存関係と MCP が起動するすべてのパッケージを、同梱のアドバイザリスナップショット(文書化された実在のバックドアの手選定リストに、LLM/MCP/RAG パッケージのウォッチリスト向け HIGH/CRITICAL OSV アドバイザリを加えたもの。
scripts/sync-advisories.jsによって再生成)と照合します。毎回のスキャンでオフライン実行され、フラグは不要です。CVE は、固定されたバージョンが影響範囲内に 証明可能に 含まれる場合にのみ発火します。文書化された悪意のあるパッケージは、範囲があいまいな場合でも発火します。バックドアのインストールは取り返しがつかないからです。 - ローカルファースト。 何もあなたのマシンから外部に出ません。
他ツールとの比較
SecureAI-Scan は、一般的な SAST ツールやコンテナ/IaC スキャナーの代替ではありません。それらと併用するものであり、置き換えるものではありません。LLM/MCP/RAG の攻撃対象領域に特化して設計されており、フラットなキーワード検出よりもデータフローの証拠を重視しています。
| SecureAI-Scan | Semgrep (OSS rules) | Trivy | GitHub Advanced Security | |
|---|---|---|---|---|
| プロンプトインジェクション(source→sink トレース) | ✅ インポート解決済みデータフロー | ⚠️ パターンルールのみ、コミュニティ保守 | ❌ | ⚠️ CodeQL なら可能だが、AI 特化のルールセットなし |
| MCP ツールポイズニング / 設定リスク | ✅ MCP007–010、設定スキャナー | ❌ | ❌ | ❌ |
Agent Skill ポイズニング(SKILL.md) | ✅ 回避耐性あり、バンドル認識 | ❌ | ❌ | ❌ |
| RAG / ベクターストアの設定ミス | ✅ VEC001–004 | ❌ | ❌ | ❌ |
| 既知の悪意ある AI パッケージアドバイザリ | ✅ DEP003、オフライン、バージョン認識 | ❌ | ⚠️ 一般的な CVE フィード、AI 特化ではない | ⚠️ Dependabot、一般的な CVE フィード |
| 一般的な SAST(SQLi、XSS、パストラバーサル) | ❌ 設計上スコープ外 | ✅ | ❌ | ✅ |
| コンテナ / IaC スキャン | ❌ | ❌ | ✅ | ⚠️ CodeQL/Actions 経由 |
| 証拠レベル(proven/likely/heuristic) | ✅ | ❌ 検出結果はフラット | ❌ | ⚠️ CodeQL には一部あるが、AI 向け調整はされていない |
| SARIF 出力(GitHub コードスキャン) | ✅ | ✅ | ✅ | ネイティブ |
| オフライン実行、アカウント不要 | ✅ | ✅(OSS ルール) | ✅ | ❌ GitHub が必要 |
すでに Semgrep や GHAS を実行している場合は、それらを維持してください。SecureAI-Scan は、それらがまったくモデル化していないリスク面を補うために追加します。
先に質問したいですか? 無料の SecureAI-Scan AI Security Advisor on ChatGPT をお試しください。
GitHub や Twitter で見つけた MCP サーバーを実行しようとしていますか? まずそのツールの説明を MCP X-Ray に貼り付けてください。ブラウザ上で、隠れた Unicode、注入された命令、既知の悪意あるパッケージをチェックします。インストールは不要です。
動作の確認
スキャナーがエンドツーエンドでトレースする攻撃形状:
| MCP ツールポイズニングのデータフロー | RAG コンテキストインジェクションのデータフロー |
|---|---|
![]() | ![]() |
コマンド
95% の場面で必要なコマンド:```bash secureai-scan scan .
必要なものはすべてそこに揃っています。`secureai-scan scan . --help` を実行すれば、これらすべてがターミナルに同じグループ分けで表示されます。
**日常使い**
| フラグ | 説明 |
|------|---------------|
| *(なし)* | `proven` + `likely` の検出結果 — デフォルト。フラグ不要 |
| `--paranoid` | `heuristic` 層の検出結果も含める |
| `-s, --severity <level>` | `low`\|`medium`\|`high`\|`critical` 以上の深刻度の検出結果のみ表示 |
| `--output <file>` | 完全なレポートを書き出す — `.sarif`(GitHub code scanning)、`.json`、`.md`、`.html` に対応 |
**実行するルールの範囲**
| フラグ | 説明 |
|------|---------------|
| `-r, --rules <list>` | 指定したルール ID のみ実行。例: `AI001,MCP007` |
| `--only-ai` / `--only-mcp` / `--only-vec` / `--only-skl` | 1つのルールカテゴリのみ実行 |
| `--check-dependencies` | `package.json`/`requirements.txt` を npm/PyPI レジストリと照合し、タイポやハルシネーションされたパッケージを確認(`DEP001`/`DEP002`)。`-r` でこれらのルールを直接選択した場合は自動で有効化されるため、両方を指定するのを覚えておく必要はありません。`DEP003`(既知の悪意あるパッケージ)には不要で、これは常にオフラインで実行されます |
**CI / ワークフロー**
| フラグ | 説明 |
|------|---------------|
| `--fail-on <severity>` | この深刻度以上の検出結果があれば終了コード `1` を返す |
| `--baseline <file>` | 保存済みベースラインに対して新規/変更された問題のみを追跡 |
| `--policy <file>` | `.secureai-policy.json` からしきい値、スキップするパス、ブロックするルールを読み込む(存在すれば自動検出 — `secureai-scan init` で作成されます) |
**高度な設定**
| フラグ | 説明 |
|------|---------------|
| `--min-confidence <0-1>` | `--paranoid` より細かい制御: 正確な信頼スコア未満の検出結果を非表示(`0.9` proven / `0.65` likely / `0.35` heuristic) |
| `--limit <n>` | ターミナルに表示するルールグループの最大数(デフォルト `10`)— 完全な詳細は常に `--output` に出力されます |
| `--debug` | スキャンしたすべてのファイルと実行されたルールを出力 |
**インストール前にスキャン — クローン不要、設定不要:**```bash
secureai-scan skill anthropics/skills # a GitHub "owner/repo" shorthand
secureai-scan skill https://github.com/… # or a full git URL
secureai-scan skill ./some/local/skill-dir # or a local path
secureai-scan mcp some-mcp-server-package # a bare npm package name
secureai-scan mcp owner/mcp-server-repo # or git, same as `skill`
skill と mcp はターゲットを取得してスキャンし、取得したコピーを削除します(代わりに検査する場合は --keep)。取得されたものが実行されることは決してありません。npm ターゲットは npm pack でダウンロードされます — tarball のみで、install もライフサイクルスクリプトもありません — また git ターゲットは単純な git clone --depth 1 です。これが最も重要となる瞬間です。スキルが ~/.claude/skills/ に配置される前、またはサーバーが .mcp.json に配置される前であって、後ではありません。
その他のコマンド:```bash secureai-scan bom . --output AI_BOM.md # AI Bill of Materials secureai-scan explain AI001 # why + exploit + fix example, for any rule secureai-scan threat-model . # THREAT_MODEL.md with the OWASP coverage matrix secureai-scan init # policy file + CI workflow, one-time setup
コード内のレビュー済みの検出結果を抑制する:```ts
// secureai-ignore AI001: reviewed, input sanitized via allowlist
GitHub Action```yaml
name: SecureAI-Scan on: [pull_request] permissions: contents: read security-events: write jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: akanthed/[email protected] with: scanner-version: 0.9.0 fail-on: high
検出結果はPR上とリポジトリのSecurityタブにインラインアノテーションとして表示されます。(`secureai-scan init` はCLIを直接使用して同等のワークフローを生成します。)
スキャン結果はクリーンですか? ご自身のREADMEにバッジを追加してください:```md
[](https://github.com/akanthed/SecureAI-Scan)
Rules
39のルール。公式の OWASP Top 10 for LLM Applications (2026) にマッピングされており、さらに該当する場合は OWASP Top 10 for Agentic Applications (2026, ASI)、OWASP MCP Top 10 (2025)、EU AI Act の条文にも対応しています。バージョン管理された2026年の対象範囲と制限 を参照してください。threat-model はスキャンした各プロジェクトのマトリクスを表示します。
| Rule | 証明する内容 | OWASP |
|---|---|---|
| AI001 | ユーザー入力がシステム/開発者プロンプトに流れ込む(関数/ファイル境界を越えてソース→シンクを追跡) | LLM01 |
| AI002 | プロンプト内容またはシークレットがログに書き込まれる(LLM SDK を使用するファイル内) | LLM02 |
| AI003 | リクエストハンドラ内で、その前に認証チェックがない LLM 呼び出し | LLM06 |
| AI004 | ユーザー/セッションオブジェクト全体がプロンプトにシリアライズされる(フィールド選択はフラグされない) | LLM02 |
| AI005 | LLM 出力が eval/exec/SQL/HTML シンクに到達する | LLM10 |
| AI006 | 影響度の高いツール(delete、pay、deploy など)が承認ゲートなしで公開されている | LLM03 |
| AI007 | 取得した RAG コンテンツが特権プロンプトに挿入される | LLM01 |
| AI008 | システムプロンプトテキストに埋め込まれたシークレット | LLM08 |
| AI009 | 無制限のユーザー入力 / トークン上限の欠如 | LLM06 |
| AI010 | 取得した外部コンテンツがプロンプトに流れ込む | LLM01 |
| AI011 | エージェント出力が後続の呼び出しでシステムロールに昇格する | LLM03 |
| AI012 | LLM 出力がスキーマ検証なしで解析される | LLM10 |
| MCP001 | MCP ツールメタデータが検証なしでシステムプロンプトに到達する | LLM01 |
| MCP002 | MCP サーバー URL がユーザー入力から構築される | LLM04 |
| MCP003 | MCP ツール結果がシステムロールに昇格する | LLM10 |
| MCP004 | MCP サーバーがバージョン固定されていない npx -y パッケージとして起動される | LLM04 |
| MCP005 | コミットされた MCP 設定にシークレットがインラインで含まれている | LLM02 |
| MCP006 | 平文 HTTP 上の MCP サーバー | LLM04 |
| MCP007 | MCP ツール名または説明に隠された不可視/双方向 Unicode | LLM01 · MCP03 |
| MCP008 | MCP ツール説明内のエージェント指向インジェクションフレーズ | LLM01 · MCP03 |
| MCP009 | 別のツールへの呼び出しを誘導するツール説明(シャドーイング) | LLM01 · MCP03 |
| MCP010 | ユーザー入力から構築される MCP stdio サーバーのコマンド/引数(RCE) | LLM04 · MCP05 |
| SKL001 | Agent Skill バンドル内のどこかに存在する不可視/双方向 Unicode | LLM01 |
| SKL002 | スキルの説明または本文におけるエージェント指向インジェクション表現(難読化を通じて一致) | LLM01 |
| SKL003 | スキルの内容が別のスキルの使用時期/方法を誘導する(シャドーイング) | LLM01 |
| SKL004 | 段階的/自己展開型ペイロード:不透明なブロブ + それをデコードして実行する指示 | LLM04 · MCP04 |
| SKL005 | バンドル付随ファイルにおける資格情報の読み取り + ハードコードされた外部送信 | LLM02 · MCP04 |
| SKL006 | Claude Code の動的コンテキストインジェクション構文(!`cmd`/```!)による、ツール権限ゲート前のロード時コマンド実行 | LLM04 · MCP05 |
| SKL007 | スキルの allowed-tools frontmatter におけるスコープ無制限の Bash 許可 | LLM03 |
| SKL008 | スキルが外部 URL から指示を取得し、エージェントにそれに従うよう指示する(「Circus of Skills」) | LLM04 |
| SKL009 | スキルが別のコンテキストファイル(MEMORY.md/SOUL.md/AGENTS.md/CLAUDE.md)に書き込むことでバックドアを仕掛ける | LLM05 |
| SKL010 | スキルの frontmatter またはバンドルされた設定ファイルにおける安全でない YAML/JSON デシリアライゼーションタグ | LLM04 |
| VEC001 | テナント/ユーザーフィルタなしのベクトル検索 | LLM09 |
| VEC002 | 無制限またはユーザー制御の検索制限 | LLM06 |
| VEC003 | 共有ベクトルストアに取り込まれるユーザーコンテンツ | LLM05 |
| VEC004 | テナント/名前空間タグ付けなしの取り込み | LLM09 |
| DEP001 | 依存関係名がレジストリに見つからない(オプトインの --check-dependencies) | LLM04 |
| DEP002 | 人気パッケージから1編集で到達できる依存関係名(オプトイン) | LLM04 |
| DEP003 | 文書化された悪意のあるリリースまたは重大な CVE がある依存関係 — スキャンごとにオフラインでチェックされ、バージョン範囲に対応(postmark-mcp、mcp-remote CVE-2025-6514 など) | LLM04 · MCP04 |
secureai-scan explain <RULE_ID> は、任意のルールについてエクスプロイトのウォークスルーと、修正前/修正後のコード例を提供します。
アーキテクチャ
3つの独立したスキャン面が、1つのマージ済み・重複排除済みの検出リストに集約されます:``` ┌─────────────────────┐ *.ts / *.js ───▶ │ ts-morph AST rules │───┐ │ (import-resolved │ │ │ sinks + dataflow) │ │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ ┌──────────────┐ ┌─────────────────┐ *.py ───▶ │ tree-sitter AST + │───┼───▶ │ scan.ts │───▶ │ evidence filter │ │ local taint flow │ │ │ merge/dedupe│ │ → confidence │ └─────────────────────┘ │ │ + suppress │ │ → severity │ │ │ (// secure- │ │ → baseline diff │ .mcp.json, ┌─────────────────────┐ │ │ ai-ignore) │ │ → report │ SKILL.md ───▶ │ Config/bundle scan │──┘ └──────────────┘ └─────────────────┘ │ (off-disk, evasion- │ │ │ resistant) │ ▼ └─────────────────────┘ terminal · sarif · json · md · html
package.json, requirements.txt ─▶ dependency-guard.ts (advisories.ts, offline, version-aware)
各ASTルールは、実インポートを通じて既知のSDKに解決された場合にのみ、関数を「LLM呼び出し」と呼びます。名前の一致だけでは決して判定しません。各サーフェスの完全な内訳については [`docs/Architecture.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/Architecture.md) を、エビデンス層の契約の仕組みについては [`docs/DetectionEngine.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/DetectionEngine.md) を参照してください。
## MCP server (Claudeから使用する)
このパッケージには、`scan_repository`、`explain_rule`、`generate_bom`、`scan_untrusted_target` を公開するMCPサーバーが同梱されています(Claudeがインストールを推奨する前にスキルまたはMCPサーバーを取得してスキャンします — `skill`/`mcp` CLIコマンドと同じ、実行せずに取得する動作です):```json
{
"mcpServers": {
"secureai-scan": {
"command": "node",
"args": ["/path/to/secureai-scan/mcp-server/index.js"]
}
}
}
Claude Skill
Claude Code / Claude.ai ユーザーの場合、skills/secureai-scan/SKILL.md は Claude にスキャンを実行するタイミング(AI/LLM コードのレビュー、またはインストール前に MCP サーバー/Agent Skill をチェックすること)と結果の読み方を教えます。上記の MCP サーバーとは異なり、実行するための別プロセスは不要です。使用するには skills/secureai-scan/ ディレクトリを .claude/skills/ にコピーします。
回避耐性
2026年7月、2件の公開研究により、Agent Skill スキャナが簡単にバイパスされることが示されました。
Cloak and Detonate(Ji、Xu、Li、Gao、Wei、Wang & Cheung — HKUST、arXiv:2607.02357)は、1,613 件の実在する悪意のあるスキルを使用して、公開されている9つのスキルスキャナに対する敵対的研究を実施しました。ペイロードを完全に保持する2つの攻撃ファミリは以下のとおりです。
- Reify — ルールが一致するバイトを書き換えますが、エージェントは実行時に元のバイトを再構成します。ほとんどの静的スキャナで >80% のバイパス。
- Disperse / SFS packing — ペイロードをルールのスコープ外に移動します。スキャナがスキップするディレクトリ内、リネームされた拡張子の背後、または
.git/にアーカイブ・エンコードして配置し、初回実行時に再構築する無害なカバー用SKILL.mdを置きます。テストしたすべてのスキャナで ≥90% のバイパス、ほとんどでは ≥96%。あるハイブリッドスキャナの検出率は約99%から約10%に低下しました。
別途、Gecko Security(VentureBeat)は *.test.ts ファイルにペイロードを同梱しました。公開されているすべてのスキャナはそれをスキップしましたが、Jest と Vitest はそれらのファイルを自動検出し、次の npm test で実行します。
SecureAI-Scan は公開された各手法を処理します。以下の各行には、test/deobfuscate.test.js 内の対応するテスト、または test-fixtures/vulnerable/skills/ 内のフィクスチャがあります。
| 手法(論文での名称) | 例 | 処理方法 |
|---|---|---|
| ゼロ幅挿入 | Ignore all previous… | テキストは不可視文字を除去したバリアントと照合されます |
| 紛らわしいグリフ | сurl(キリル文字 с) | 照合前にホモグリフを ASCII に畳み込みます |
| 大文字小文字の反転 | EvAl | すべてのコンテンツパターンは大文字小文字を区別しません |
| 変数スプライシング | 'cu' + 'rl' | 照合前に隣接する文字列リテラルを結合します |
| 行単位の分割 | ev⏎al(x) | 単語内の改行を追加バリアントとして結合します |
| ファイル単位の抽出 | ソースされたヘルパー内のペイロード | SKILL.md だけでなくバンドル全体がスキャンされます |
| ディレクトリの再配置 | scripts/x.sh → build/x.sh | バンドル内にディレクトリスキップリストはありません |
| 拡張子のリネーム | x.sh → x.txt | ファイルは拡張子ではなく内容でスキャンされます |
| サイズパディング | スキャナの上限を超えるパディング | サイズ超過ファイルは先頭から読み取られ、決してスキップされません |
| SFSパッキング | .git/skillpack.dat 内のペイロード | バンドルの .git/ 配下にある非 git ファイルは proven と判定されます (SKL004) |
| テストファイルのステージング | *.test.ts 内のペイロード | バンドルスキャンは意図的にテストパスを降格しません (SKL005) |
これによって精度契約は弱まりません
難読化解除は通常、精度に対するリスクです。マッチが増えればノイズも増えます。ここではロジックが逆転しています。難読化解除後にのみ現れるマッチは、降格ではなく proven に昇格します。 通常のドキュメントに「ignore previous instructions」の中のゼロ幅ジョイナーは含まれず、curl の中にキリル文字 с も含まれません。隠蔽はそれ自体が意図を示す積極的な証拠です。
比較対象は生のマッチの集合であり、「生のテキストが少しでもマッチしたかどうか」ではありません。そうでなければ、攻撃者は無害なフレーズを1つそのまま残すだけでシグナルを隠蔽できてしまいます。
新しい2つのバンドルルールは、単独のキーワードではなく、AND組み合わせでのみ発動します。
- SKL004 は、不透明なブロブと、そのブロブを名前で参照する展開ディレクティブを必要とします。無関係なバイナリアセットの隣で
tar -xに言及する README では不十分です。実際のアーカイブ(gzip/zip/png/pdf/wasm — マジックバイトで判定され、拡張子ではない)は、どのように圧縮されていても、そもそも「不透明」ではありません。 - SKL005 は、具体的な資格情報のシグナル(パス(
~/.aws/credentials、単語 "token" ではない)、または環境変数の一括列挙(os.environ.items()、os.environ["API_KEY"]ではない))および、ハードコードされた非ローカルホストへの外部送信が同じファイル内の互いに25行以内にあること、または1回以上のリネームを経て再割り当てされた後に実行されるリモートフェッチを必要とします。ある関数で~/.npmrcを読み取り、40行後にレジストリを呼び出す公開ヘルパーはクリーンとみなされ、API コールのために名前付きの環境変数を1つ読むだけのコードはフラグされません。どちらの形状も安全なフィクスチャとして固定されています。
自作のフィクスチャだけでなく、実世界の2つのコーパスでも検証されています。anthropics/skills の全18個の実際のスキルバンドルで0件の検出、vercel/ai の全14個でも0件、cisco-ai-defense/skill-scanner のラベル付き評価コーパスで 6/6 正解(20スキル、各スキルに _expected.json 判定付き)、安全とラベル付けされたものに対する誤検出はゼロです。テストとベンチマーク を参照してください。
テストとベンチマーク
3つのレイヤーがあります。1つだけではスキャナの主張を信頼するには不十分です。適合率(precision)と再現率(recall)は異なる障害モードであり、両方がチェックされます。
1. フィクスチャコーパス — 適合率 + 再現率。すべてのビルドで実行されます。```bash npm test
[`test-fixtures/vulnerable/`](https://github.com/akanthed/secureai-scan/blob/HEAD/test-fixtures/vulnerable) と [`test-fixtures/safe/`](https://github.com/akanthed/secureai-scan/blob/HEAD/test-fixtures/safe) は一緒にスキャンされます。すべての脆弱なフィクスチャは、期待されるルールを `proven`/`likely` のエビデンスで発火させなければならず(再現率)、すべての安全なフィクスチャは `proven`/`likely` の検出結果を**ゼロ**にしなければなりません(適合率)。高速で決定的ですが、スキャナーがテスト用に特別に書かれたコードに対してのみ正しく動作することを証明するにすぎません。
**2. 実世界の回帰ベンチマーク — 私たちが書いていない公開リポジトリに対するもの。**```bash
npm run regression # scan the full curated repo set
npm run regression -- --fresh # re-clone everything first
npm run regression -- openai-node # scan just one repo by name
npm run regression -- --update-baseline # accept the current findings
scripts/regression-scan.js は、厳選された多様な実在の公開リポジトリ(OpenAI/Anthropic/Vercel AI SDK、公式 MCP サーバーと TypeScript SDK、LlamaIndex、さらにスキルバンドル対応のための anthropics/skills と cisco-ai-defense/skill-scanner — TS と Python、SDK 利用者のサンプルコードと SDK 作者のソースの両方をカバー)をクローンし、ビルド済み CLI でそれぞれをスキャンします。
既に test/regression-baseline.json に含まれていない proven/likely の検出結果があると 非ゼロの終了コードで終了します — これは、ソース行と照合して確認済みの検出結果を手作業でレビューした記録です。フィンガープリントは行番号ではなく repo|rule|file であるため、通常の上流リポジトリの変更ではノイズが発生しません。新しいフィンガープリントは、スキャナーが正当性を説明しなければならない主張です。それが本当の問題でない場合、それはルールのバグであり、根本原因で修正され、新しい test-fixtures/safe/ フィクスチャとして固定されます。読んでいない検出結果をベースラインに登録すると、この仕組み全体が無意味になります。
スキルバンドルのカバレッジには専用の行が設けられています。なぜなら cisco-ai-defense/skill-scanner の evals/ コーパスにはラベルが付いているからです — その20個のフィクスチャはそれぞれ _expected.json の判定結果を同梱し、文字通り malicious/ または safe/ という名前のディレクトリ配下に置かれているため、精度チェックだけでなく再現率チェックも兼ねています: 対象範囲内の悪意のあるフィクスチャは6/6で検出され、safe とラベル付けされたものには0件の検出、さらに anthropics/skills の実在する18バンドルすべてと vercel/ai の14バンドルすべてで0件の検出です。(残りの Cisco カテゴリ — SQL インジェクション、パストラバーサル、リソース枯渇、関数引数の汎用的な eval()、4ファイルに意図的に分割されたペイロード — は、文書化された LLM/MCP/RAG のスコープ外であるか、同一ファイル内の結合分析の範囲を超えています。それぞれの具体的な理由については 0.6.0 のチェンジログエントリ を参照してください。)
当初の精度修正を推進した実行の before/after 履歴(デフォルトのエビデンスレベルでの検出結果、--paranoid なし):
| リポジトリ | 修正前 | 修正後 | 問題だった点 |
|---|---|---|---|
| vercel/ai | 773 | 1 | examples/、トップレベルの tests/、およびハイフン付きの ecosystem-tests/ 形式のディレクトリが低信頼パスとして認識されませんでした。chunks(一般的なストリーミング応答の変数)が曖昧性のない RAG エビデンスとして扱われました |
| openai/openai-node | 47 | 0 | 同じパス検出のギャップが SDK 自身の examples//ecosystem-tests/ に適用されました |
| anthropics/anthropic-sdk-typescript | 2 | 0 | トップレベルの tests/ ディレクトリに対する同じパス検出のギャップ |
| modelcontextprotocol/typescript-sdk | 3 | 0 | token_endpoint/tokenType 形式の OAuth メタデータフィールドが漏えいしたシークレットとしてフラグ付けされました |
| run-llama/llama_index | 18 | 15 | Python のチェックが、「system prompt」を含む任意の description= フィールドを、文脈に関わらず proven の MCP ツールポイズニングとしてフラグ付けしました。残りの15件は、ライブラリ自身の汎用リトリーバー定義に対する VEC001 のヒットです — アプリケーションコードではなくベクターDB SDK のソースをスキャンしているため、確認すべきフィルタは存在し得ません。これはバグではなく、正直で本質的な限界です |
現在の実行結果(2026-08-06) — バージョン管理されたエビデンスは docs/benchmarks/v0.9.0.json に記録されています:
| リポジトリ | 検出件数 | ルール | ステータス |
|---|---|---|---|
| openai-node、anthropic-sdk-typescript、anthropic-sdk-python、modelcontextprotocol/typescript-sdk、modelcontextprotocol/servers | 0 | — | クリーン |
| anthropics/skills(実在する18のスキルバンドル) | 0 | — | クリーン — SKL001–005 の純粋な精度チェック |
| vercel/ai(5,691ファイル) | 0 | — | トリアージ前は 40件(AI001、AI003、AI005、AI010、MCP002)— すべてをソースと照合して手作業でレビューし、誤検知と確認済み。3つの独立した根本原因のバグに起因(下記参照)、修正後、完全再スキャンでクリーンであることを再確認 |
| run-llama/llama_index | 46 | VEC001 | バグではなく本質的な限界 — ライブラリ自身の汎用リトリーバー定義であり、検出対象となるテナントフィルタは存在し得ない |
| cisco-ai-defense/skill-scanner | 7 | SKL001、SKL002、SKL005 | すべて malicious/ とラベル付けされたフィクスチャに対するもの — 対象範囲内は6/6、safe/ とラベル付けされたものには0件 |
vercel/ai のトリアージでは、根本原因が特定された実際のバグが3件見つかりました — いずれも v0.6.0 のスキルルール固有のものではなく、多くのルールで使用される共通ロジックにありました:
resolveLlmSinkは、メソッド名に関係なく、LLM SDK モジュールに解決されたすべての呼び出しをモデル呼び出しとして扱っていました —isToolUIPart(aiパッケージがgenerateTextと並んでエクスポートする型ガード)を LLM 呼び出しとしてフラグ付けしました。これだけで5つの検出グループのうち3つ(AI001、AI003、AI010)の原因となりました。- AI005 の
DANGEROUS_CALLEESには SQL インジェクション型シンクのための"query"が含まれていますが、"query"は正当な LLM/エージェント呼び出しの動詞でもあります —claudeSdk.query({ prompt, options })(Claude Agent SDK 自身のモデル呼び出し)が、単にメソッド名が共通であるという理由で「危険なシンクに渡された LLM 出力」としてフラグ付けされました。 REQUEST_SOURCES(MCP002、MCP010、VEC003 で同一に複製されている)は、裸の"params."にマッチしていました — これは必ずしも HTTP リクエストデータではなく、慣例的にparamsと名付けられた任意の関数パラメータにマッチします。URL スキーム検証器(assertOpenLinkParams(params: unknown))が「ユーザー入力からの MCP サーバー URL」としてフラグ付けされました。
3つすべては(特定の呼び出し箇所ではなく)根本原因で修正され、test-fixtures/ 配下に恒久的なフィクスチャとして固定されています。詳細は CHANGELOG.md に記載されています。
3. 脆弱バージョン vs パッチ適用済みバージョンの検証 — 精度だけでなく再現率も証明します。
上記の2つのレイヤーは、スキャナーが安全なコードに対して検出を行わないことだけを確認します。DEP003 のアドバイザリチェックは逆の方法で検証されます: パッケージを脆弱性が文書化されたバージョンに固定してフラグが付くことを確認し、次にパッチ適用済みバージョンに固定してフラグが付かないことを確認します。```bash
node --test test/dependency-guard.test.js
カバー内容: `[email protected]`(CVE-2025-6514、脆弱)はフラグ付き / `[email protected]`(パッチ適用済み)はクリーン。`[email protected]`(バックドアの前)はクリーン / `[email protected]`(バックドア後 — 悪意のあるパッケージに正当なパッチは存在しない)は依然としてフラグ付き。`llama-cpp-python==0.2.71`(CVE-2024-34359、OSV 生成セット由来)はフラグ付き / `==0.2.72`(パッチ適用済み)はクリーン、PyPI の名前正規化(`llama_cpp_python`)でも同様。また、`langchain>=0.1.0` 形式のピン留めされていない指定子は、デフォルトレポートで**ゼロ**件の検出結果になる。このテストを構築したことで実際のギャップが明らかになった: `DEP003` はアドバイザリをパッケージ名だけで照合しており、宣言されたバージョンをアドバイザリの影響を受ける範囲と実際には比較していなかった — [`src/scanner/semver.ts`](https://github.com/akanthed/secureai-scan/blob/HEAD/src/scanner/semver.ts) で修正済み。
あいまいさは、アドバイザリの種類ごとに意図的に異なる方法で解決される。**悪意のある**パッケージは、宣言されたバージョンを解決できない場合でも検出される — バックドアのインストールは取り返しがつかないため、フラグを立てる方向に倒れる。**CVE** は、宣言されたバージョンが影響を受ける範囲内にあると証明できる正確なピンである場合にのみ `proven` で検出される。ピン留めされていないが影響を受ける可能性がある場合は `heuristic`(`--paranoid` のみ)に格下げされる。悪意のある種類のルールを162エントリのCVEスナップショットに適用すると、`langchain>=0.1.0` を宣言するすべてのリポジトリに重大な検出結果が出ることになる — 規模が大きくなると対応不能なノイズだ。
## ロードマップ
出荷済みの機能と計画中の機能については [`ROADMAP.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/ROADMAP.md) を参照してください。両言語エンジンは AST ベースです: TypeScript/JavaScript には ts-morph、Python には Tree-sitter を使用しています。Python のインポート、呼び出し、代入、デコレータ、スコープ、キーワード引数、辞書フィールド、文字列はすべて構文ノードです。対象コードがインポートまたは実行されることはなく、Python インタープリタも不要です。残りの Python のギャップは、解析ではなく、関数間/ファイル間のテイント深さに限定されています。スキャンのパフォーマンスと既知の制限は [`docs/Performance.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/Performance.md) に文書化されています。
## コントリビューション
コントリビューションは歓迎します — ワークフローについては [`CONTRIBUTING.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/CONTRIBUTING.md) を、上記の精度基準を満たす検出ルールの追加方法については [`docs/WritingRules.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/WritingRules.md) / [`docs/RuleDevelopment.md`](https://github.com/akanthed/secureai-scan/blob/HEAD/docs/RuleDevelopment.md) を参照してください。新しいルールにはそれぞれ、[`test-fixtures/vulnerable/`](https://github.com/akanthed/secureai-scan/blob/HEAD/test-fixtures/vulnerable) と [`test-fixtures/safe/`](https://github.com/akanthed/secureai-scan/blob/HEAD/test-fixtures/safe) の両方にフィクスチャ、`src/scanner/catalog.ts` へのエントリ、`test/corpus.test.js` へのテストケースが必要です — `npm test` がこの3つすべてを検証します。
## ライセンス
MIT © Akshay Kanthed

