mcpField
S
security-scanner

security-scanner

github.com/hiroro-workセキュリティ4783 回インストール1 日前に更新
リポジトリ

security-scanner について

security-scannerは、Claude Codeのプラグインや複数のエージェント向けスキルを監査するスキルです。実行可能な内容と言語による指示を調べ、対象範囲や信頼リストを設定してローカル環境または公開GitHubリポジトリをスキャンできます。

主な機能

  1. 01プラグインとスキルのスキャン
  2. 02公開GitHubリポジトリの確認
  3. 03コードと言語による指示の分析
  4. 04ユーザーまたはプロジェクト範囲の指定
  5. 05対象エージェントと信頼元の設定
  6. 06セキュリティレポートの生成

活用シーン

  1. 01インストール済みプラグインとスキルの監査
  2. 02GitHub上のスキルディレクトリのスキャン
  3. 03スクリプト内の危険なコマンドの確認
  4. 04信頼リストにある対象の除外

インストール

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

$npx skills add https://github.com/hiroro-work/claude-plugins --skill security-scanner

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

同梱ファイル.claude-plugin/plugin.jsonREADME.md

詳細

セキュリティスキャナー

使用方法

/security-scanner              # Scan all (plugins + skills)
/security-scanner --user       # Scan user-level only (~/.claude/)
/security-scanner --project    # Scan project-level only (.claude/)
/security-scanner --all        # Scan ALL (ignore trusted sources and self-exclusion)
/security-scanner <url>        # Scan from GitHub URL (public repos only)
/security-scanner --url <url>  # Same as above (explicit form)

スキャンプロセス

ステップ 1:設定の読み込み

次の場所で security-scanner.local.md を検索します。

  1. プロジェクトレベル:.claude/security-scanner.local.md
  2. ユーザーレベル:~/.claude/security-scanner.local.md

優先順位のルール:

  • 両方のファイルが存在する場合は、プロジェクトレベルの設定のみを使用します(プロジェクトレベルが優先されます)
  • いずれか一方のみが存在する場合は、そのファイルを使用します
  • どちらも存在しない場合は、デフォルト設定で続行します

選択したファイルから、次の項目を抽出します:

  • YAML フロントマターの report_language
  • YAML フロントマターの target_agents リスト
  • YAML フロントマターの trusted_marketplaces リスト
  • YAML フロントマターの trusted_plugins リスト
  • YAML フロントマターの trusted_skills リスト

デフォルト値(指定がない場合):

  • report_language:ja(日本語)
  • target_agents:["claude"]
  • trusted_marketplaces:[]
  • trusted_plugins:[]
  • trusted_skills:[]

検証:

  • report_language:任意の文字列値を指定できます(AI はその言語でレポートを生成します)
  • target_agents に含められるエージェント ID は、claude、codex、gemini、agents のみです
  • 無効なエージェント ID は、警告を出して無視されます

エラー処理:

  • ファイルが存在しても YAML 構文が無効な場合は、ユーザーに警告し、デフォルト設定で続行します(スキャンは失敗しません)
ステップ 2:スコープの決定

引数を確認し、スキャン対象を決定します。

場所のフィルター:

  • 場所フラグなし:設定済みのすべてのエージェントについて、ユーザーレベルとプロジェクトレベルの両方をスキャンします
  • --user:target_agents のすべてのエージェントについて、ユーザーレベルのパスのみをスキャンします
  • --project:target_agents のすべてのエージェントについて、プロジェクトレベルのパスのみをスキャンします

URL の検出(最優先):

  1. --url <url> が明示的に指定されている場合 → ステップ 2-URL に進みます
  2. いずれかの引数が https://github.com/ または http://github.com/ で始まる場合 → URL として扱い、ステップ 2-URL に進みます
  3. いずれかの引数が https:// または http:// で始まり、github.com ではない場合 → エラー:「サポートされていないホストです:{host}。現在サポートされているのは github.com のみです。」

特別なモード(URL がない場合):

  • --all:すべてをスキャンします(ステップ 4 のフィルタリングを完全にスキップします)

ステップ 2-URL:GitHub URL のスキャン

URL が指定されている場合(--url による指定、または自動検出)、ステップ 3~4 の代わりに次の手順に従います。

ステップ 2-URL-1:URL の解析

GitHub URL を解析して、オーナー、リポジトリ、ブランチ、パスを抽出し、スキャンの種類を判定します。

URL パターン:

  • ディレクトリ:https://github.com/{owner}/{repo}[/tree/{branch}/{path}]
  • 単一ファイル:https://github.com/{owner}/{repo}/blob/{branch}/{path}.md
  1. ホストが github.com であることを確認します
    • そうでない場合:エラー「サポートされていないホストです:{host}。現在サポートされているのは github.com のみです。」
  2. パスのセグメントから owner と repo を抽出します
  3. スキャンの種類を判定します:
    • URL に /blob/ が含まれ、.md で終わる場合 → 単一ファイルのスキャン
    • それ以外の場合 → ディレクトリのスキャン
  4. ディレクトリのスキャンの場合:
    • /tree/{branch}/{path} がある場合は、branch と path を抽出します
    • /tree/ がない場合は、branch を空(デフォルトを使用)に設定し、path を空文字列に設定します
  5. 単一ファイルのスキャンの場合:
    • /blob/{branch}/ の後から branch とファイルパスを抽出します
Step 2-URL-2: コンテンツを取得する

単一ファイルのスキャンの場合:

  1. /blob/ URL を raw URL に変換します:https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}
  2. WebFetch を使用してファイルのコンテンツを取得します
  3. 分析のため、Step 5 に直接進みます

ディレクトリのスキャンの場合:

  1. ディレクトリを取得します:https://api.github.com/repos/{owner}/{repo}/contents/{path}?ref={branch}
    • branch が空の場合は、?ref= パラメーターを省略します(デフォルトブランチを使用)
    • 次のプロンプトを指定して WebFetch を使用します:"Extract the JSON array of files. For each item, return: name, type (file/dir), download_url"
  2. コンテンツの種類を判定し、それに応じて取得します:
    • .claude-plugin/ ディレクトリがあり、その一覧に plugin.json が含まれている場合:プラグイン全体をスキャンします(すべてのプラグインファイルを取得)
    • skills/ がある場合:スキルをスキャンします(スキルのディレクトリを取得)
    • SKILL.md がある場合:単一のスキルディレクトリをスキャンします(ディレクトリ内のすべてのファイルを取得)
    • 上記のいずれにも該当しない場合:エラー "No scannable content found. Expected .claude-plugin/plugin.json, skills/ directory, or SKILL.md." を返します。
  3. 必要なディレクトリとファイルを再帰的に取得します:
    • .claude-plugin/ → plugin.json を取得
    • skills/ → サブディレクトリを取得 → 各スキルディレクトリ内のすべてのファイルを取得
    • agents/ → すべての *.md ファイルを取得(存在する場合)
    • hooks/ → hooks.json を取得(存在する場合)
    • フックまたはスキルが呼び出すすべてのスクリプト(例:skills/*/scripts/**、skills/*/*.sh)
    • commands/ → すべての *.md ファイルを取得(存在する場合)
Step 2-URL-3: ファイルのコンテンツを取得する

プラグインのスキャンの場合、以下を取得します:

  • .claude-plugin/plugin.json(hooks フィールドがあればそれも含む)、README.md、.mcp.json、hooks/hooks.json
  • skills/ 内のすべてのファイル、agents/*.md、commands/*.md、およびフックまたはスキルが呼び出すすべてのスクリプト

スキルディレクトリのスキャンの場合(skills/ または単一のスキル)、以下を取得します:

  • スキルディレクトリ内のすべてのファイル

次のプロンプトを指定して WebFetch を使用します:"Return the raw file content exactly as-is"

Step 2-URL-4: エラー処理
  • 404:リポジトリまたはパスが見つかりません
  • 403/401:プライベートリポジトリ(未対応)またはレート制限超過
  • その他のエラー:エラーメッセージを報告します

すべてのファイルを取得したら、分析のためStep 5に進みます。


Step 3: スキャン対象を取得する

Step 2 で判定した範囲と Step 1 の target_agents に基づいて、対象を収集します:

プラグインの場合(Claude Code のみ):

ユーザーレベル:

  1. ~/.claude/plugins/installed_plugins.json を読み取ります
  2. .plugins は、各プラグイン ID(<plugin>@<marketplace>)をインストールレコードの配列に対応付けます。各 ID について、レコードの scope にかかわらず、ID とすべてのレコードの installPath を保持し、その後 installPath でスキャン対象を重複排除します
  3. ファイルが存在しない場合は、"No user-level plugins installed" と報告します

プロジェクトレベル:

  1. Glob を使用して .claude/plugins/*/ 内のプラグインを検索します
  2. プラグインが見つからない場合は、"No project-level plugins found" と報告します

スキルの場合(target_agents に基づく):

target_agents リスト内の各エージェントについて、対応するディレクトリからスキルを収集します:

エージェントのパス対応表:

エージェントプロジェクトレベルユーザーレベル
claude.claude/skills/*/~/.claude/skills/*/
codex.codex/skills/*/~/.codex/skills/*/
gemini.gemini/skills/*/~/.gemini/skills/*/
agents.agents/skills/*/~/.config/agents/skills/*/ AND ~/.agents/skills/*/

target_agents 内の各エージェントについて:

ユーザーレベル:

  1. エージェント ID に基づいてユーザーレベルのパスを特定します(上の表を参照)
  2. そのパス内のスキルディレクトリを検索します
  3. 見つかった各スキルディレクトリについて、スキャン用にパスとエージェント ID を記録します
  4. このエージェントのスキルが見つからない場合は、"No user-level skills found for {agent}" と報告します

プロジェクトレベル:

  1. エージェント ID に基づいてプロジェクトレベルのパスを特定します(上の表を参照)
  2. そのパス内のスキルディレクトリを検索します
  3. 見つかった各スキルディレクトリについて、スキャン用にパスとエージェント ID を記録します
  4. このエージェントのスキルが見つからない場合は、"No project-level skills found for {agent}" と報告します
Step 4: 対象をフィルタリングする

--all フラグが設定されている場合:この手順を完全にスキップし、すべての対象をスキャンします。

自己除外(すべての対象タイプに対して自動的に実行)

<skill base directory> は、このスキルの呼び出し時にハーネスが「このスキルのベースディレクトリ」として報告するディレクトリです。絶対パスをハードコードしないでください。

  • 比較前に正規化する:両方の側で、末尾の / を削除し、先頭の ~ を展開します
  • パスの解決:ls -ld <dir> を実行します。その出力に -> <target> が表示された場合、解決後のパスは、<target> が絶対パスならそのパス、相対パスなら <dir> を含むディレクトリを基準に結合して正規化したパスです。親ディレクトリ要素は解決しません。コマンドが失敗した場合、そのパスには解決後の形式がありません
  • 自己対象:収集された対象(プラグインのインストール記録の installPath、プロジェクトレベルのプラグインディレクトリ、またはスキルディレクトリ)がこのスキャナー自身であるのは、そのパスが <skill base directory> と等しい場合、または両者の一方が他方の / 境界で区切られたプレフィックスである場合です。収集されたパスと報告されたパスの組み合わせで比較し、その後、両方を解決したパスでも比較します
  • 自己対象はすべてスキップします。そのいずれかがプラグインのインストール記録の場合、そのプラグイン ID を共有する他の記録もすべてスキップします。スキップした各対象はパス一致として報告し、Trusted 列に計上します
  • <skill base directory> が利用できない場合:security-scanner という名前のプラグインとスキルをスキップし、名前一致として報告します
  • このスキャナー自身ではない security-scanner という名前のプラグインまたはスキルは、<skill base directory> が利用可能な場合、通常どおりスキャンします。ホスト上の別の場所にインストールされたこのスキャナーの複製も、そのような対象の1つです
プラグインの場合:

信頼できるソース:

  • マーケットプレイスが trusted_marketplaces に含まれている場合 → スキップ
  • プラグイン ID(<plugin>@<marketplace>)が trusted_plugins に含まれている場合 → スキップ
  • スキップしたプラグインは「Trusted (skipped)」として報告します
スキルの場合:

信頼できるソース:

  • スキル名が trusted_skills に含まれている場合 → スキップ(すべてのエージェントで対象)
  • スキップしたスキルは「Trusted (skipped)」として報告します
Step 5: 各プラグインを分析する

信頼済みではないプラグインごとに、次の手順を実行します。

  1. プラグインのメタデータを読む(.claude-plugin/plugin.json、README.md)ことで、明示された目的を把握します

  2. すべての実行可能コンテンツを読む:

    • skills/*/SKILL.md - スキルの定義と指示
    • agents/*.md - エージェントのシステムプロンプト(存在する場合)
    • .claude-plugin/plugin.json の hooks フィールドと hooks/hooks.json - フックの定義、およびそれらが呼び出すすべてのスクリプト(存在する場合)
    • commands/*.md - コマンドの定義(存在する場合)
    • .mcp.json - MCP サーバーの設定(存在する場合)
  3. 悪意のある意図を分析する(コードと自然言語の両方)

Step 5.5: 各スキルを分析する

信頼済みではないスキルごとに、次の手順を実行します。

  1. スキルのメタデータを読む(SKILL.md のフロントマター)ことで、明示された目的を把握します

  2. スキルディレクトリ内のすべてのファイルを読む:

    • SKILL.md - スキルの主な指示(必須)
    • ディレクトリ内のその他すべてのファイル
  3. 悪意のある意図を分析する(コードと自然言語の両方)

Step 6: 脅威の検出
コードレベルの脅威

危険なコマンドパターンを探します。

  • リモートコード実行:curl|sh、wget|bash、base64 -d|sh
  • 言語ランタイムでの RCE:python -c、perl -e、ruby -e、node -e、osascript、powershell
  • リバースシェル:nc -e、netcat、socat、mkfifo
  • システムの破壊:rm -rf /、dd if=
  • 認証情報へのアクセス:~/.ssh/、/etc/passwd、keychain
  • データの持ち出し:sshpass、外部サーバーへの scp、rsync
  • 一時ファイルの実行:chmod +x /tmp/*、mktemp と実行の組み合わせ
  • 難読化:base64/xxd/hexdump によるデコードと実行
  • パッケージインストールによる副作用:postinstall または setup.py を伴う npm install/pip install
  • 永続化:crontab、launchctl
  • 権限昇格:sudo、doas
Natural Language Threats

Read system prompts, instructions, and documentation for:

  • Data exfiltration instructions: Instructions to read sensitive files (SSH keys, credentials, API keys, private data) and send them externally
  • Hidden malicious actions: Instructions to perform harmful actions while appearing helpful
  • Deceptive instructions: Instructions that contradict the plugin's stated purpose
  • Security bypass: Instructions to ignore security warnings or bypass restrictions
  • User deception: Instructions to hide actions from the user or provide false information
  • Log/trace hiding: Instructions to delete logs, clear history, or hide evidence of actions
  • Excessive permission requests: Instructions requesting access to unrelated resources
Permission Analysis

Check if permissions match the plugin's purpose:

  • Does a "translation plugin" need Bash(*)? Suspicious.
  • Does a "git helper" need Bash(git *)? Reasonable.
  • Does a "file organizer" need access to ~/.ssh/? Suspicious.
Step 7: Generate Report

Generate the report in the language specified by report_language setting.

For Local Scans (default, --user, --project, --all)

Japanese (ja) - Default:

# セキュリティ分析レポート

## 概要
| エージェント | 種別 | 検出 | 信頼済 | スキャン | 悪意あり | 要注意 | 安全 |
|-------------|------|------|--------|----------|----------|--------|------|
| claude | プラグイン | N | N | N | N | N | N |
| claude | スキル | N | N | N | N | N | N |

注: `target_agents` に設定されたエージェントのみ表示。プラグインは常に `claude` 配下。

## 信頼済み(スキップ)
- plugin-name@marketplace(信頼済みマーケットプレイス)
- plugin-name@marketplace(自己除外: パス一致)
- skill-name (claude)(自己除外: 名前一致)
- skill-name (claude) - 信頼済みスキル

## 検出結果

### プラグイン (claude)

#### [プラグイン名]
**種別:** プラグイン
**目的:** [README/plugin.json から]
**判定:** 安全 / 要注意 / 悪意あり

**検出された問題:**
- [問題の説明、ファイル、懸念される理由]

### スキル

#### [スキル名] (claude)
**エージェント:** claude
**種別:** スキル
**場所:** ~/.claude/skills/skill-name/ または .claude/skills/skill-name/
**目的:** [SKILL.md の description から]
**判定:** 安全 / 要注意 / 悪意あり

**検出された問題:**
- [問題の説明と懸念される理由]

---

## 推奨事項

問題のある項目について:
- [ ] 安全 - 使用可
- [ ] 要確認 - [具体的な懸念点]
- [ ] 使用禁止 - [悪意のあるコンテンツを検出]

English (en):

# Security Analysis Report

## Summary
| Agent | Type | Found | Trusted | Scanned | Malicious | Suspicious | Safe |
|-------|------|-------|---------|---------|-----------|------------|------|
| claude | Plugins | N | N | N | N | N | N |
| claude | Skills | N | N | N | N | N | N |

Note: Only rows for configured `target_agents` are shown. Plugins are always under `claude`.

## Trusted (Skipped)
- plugin-name@marketplace (trusted marketplace)
- plugin-name@marketplace (self-exclusion: path match)
- skill-name (claude) (self-exclusion: name match)
- skill-name (claude) - trusted skill

## Findings

### Plugins (claude)

#### [Plugin Name]
**Type:** Plugin
**Purpose:** [from README/plugin.json]
**Verdict:** Safe / Suspicious / Malicious

**Issues found:**
- [Description of issue, file, and why it's concerning]

### Skills

#### [Skill Name] (claude)
**Agent:** claude
**Type:** Skill
**Location:** ~/.claude/skills/skill-name/ or .claude/skills/skill-name/
**Purpose:** [from SKILL.md description]
**Verdict:** Safe / Suspicious / Malicious

**Issues found:**
- [Description of issue and why it's concerning]
For GitHub URL Scans (--url)

Use the same report format as local scans, with this header added:

Japanese (ja):

  • URL: {元のURL}
  • 種別: プラグイン / スキル / 単一ファイル

English (en):

  • URL: {original URL}
  • Type: Plugin / Skill / Single file

Analysis Guidelines

  1. Consider context: A security plugin checking for rm -rf patterns is different from a plugin containing rm -rf commands
  2. Check purpose alignment: Does the code/instruction match what the plugin claims to do?
  3. Trust but verify: Read the actual content, don't just pattern match
  4. When uncertain, flag as suspicious
  5. Explain findings: Always explain WHY something is flagged

コメント