skill-vet — エージェントスキル検証ツール は何をしますか?
エージェントスキルパックをインストールする前に、1つのコマンドで検証します。このマシン外のスキル(マーケットプレイスからのダウンロード、誰かがリンクしたリポジトリ、クライアントが送信したパックなど)をエージェントがロードする前に使用してください。
コマンド
skill-vet vet <skill-pack-folder> [--json] [--strict]
(インストール方法:pipx install skill-vet または pip install skill-vet。ソースからチェックアウトした場合、同じコマンドは python3 src/skill_vet.py vet <skill-pack-folder> … となります。)
- 引数はパックのルートフォルダ(SKILL.md があるフォルダ)です。1回の実行で1つのパックを扱います。
- 終了コード:0 = 判定 CLEAN または REVIEW、1 = 判定 BLOCKED(または
--strict時の REVIEW)、2 = 入力エラー(フォルダがない、フォルダでない、引数が不正)。--jsonモードでは、すべてのエラー(引数エラーを含む)はerrorキーを持つ1つのJSONオブジェクトとして出力されます。トレースバックは出力されません。 - 読み取り専用であり、何も実行しません。 Vetはパックを静的なテキストとして読み取ります。パックのインポート、実行、シェル呼び出し、評価は一切行いません。Vet自身のソースコードはネットワークモジュールやサブプロセスモジュールを一切インポートしません。積極的に信頼していないパックに対しても安全に使用できます。
危険モデル(製品全体)
パックが危険(DANGEROUS)となるのは、以下の3つのいずれかを行う場合のみです(2026-10-30時点の運営ルール、厳密に適用):
- 盗難(STEALS) — 認証情報ストア、ブラウザプロファイル、SSHキー、環境変数のシークレットを読み取り、結果を外部に送信またはコピーする。
- スパイ(SPIES) — 画面、キーボード、マイク、カメラ、ブラウザ履歴をキャプチャし、そのキャプチャを保存または送信する。ただし、ドキュメントでキャプチャが開示されている場合は除く。
- 隠蔽送信(SENDS IN SECRET) — ペイロードや宛先が隠蔽されたネットワーク呼び出し(エンコードされたペイロードを未開示のエンドポイントに送信、ローカルファイル内容を未開示のエンドポイントに送信、パック外への書き込みを伴う送信、またはオフラインで動作すると主張するパックからの送信)。
パターンにヒットしただけでは危険判定にはなりません。 各テストは同じファイル内に証拠の組み合わせが必要であり、判定結果は両方の要素をファイルと行番号で引用します。組み合わせに満たないものは、証拠を明示した警告となります。組み合わせは以下の通り:
| 1ファイル内の証拠 | 判定 |
|---|---|
| シークレット読み取り + 送信、またはシークレット読み取り + 外部パスへのコピー/移動 | DANGER_STEALING (BLOCKED) |
| キャプチャ + (送信または保存)、SKILL.md/README.mdでキャプチャ種別が未開示 | DANGER_SPYING (BLOCKED) |
| 送信 + エンコードされたペイロード、エンドポイントが未開示または非リテラル | DANGER_HIDDEN_SENDING (BLOCKED) |
| 送信 + パック外部ファイルの読み取り、エンドポイントが未開示 | DANGER_HIDDEN_SENDING (BLOCKED) |
| 送信 + パック外部への書き込み、エンドポイントが未開示 | DANGER_HIDDEN_SENDING (BLOCKED) |
| 送信 + ドキュメントでオフライン/ローカルのみと主張 | DANGER_HIDDEN_SENDING (BLOCKED) |
| シークレット読み取り、同じファイルに外部送信なし | SECRET_ACCESS (WARN) |
| ドキュメントで言及されていないエンドポイントへの送信、隠蔽の組み合わせなし | UNDISCLOSED_NETWORK (WARN) |
| 確認可能なリテラルURLなしでの送信 | DYNAMIC_ENDPOINT (WARN) |
| 開示されたエンドポイントへのエンコードされたペイロード | ENCODED_PAYLOAD (WARN) |
| キャプチャ + 保存/送信、キャプチャがドキュメントで開示 | DISCLOSED_CAPTURE (WARN) |
| キャプチャ、保存や送信なし | CAPTURE_CAPABILITY (WARN) |
判断基準(明確に記載):
- 盗難には隠蔽は不要です。認証情報をドキュメントに記載されたエンドポイントに送信する場合も盗難です。ドキュメントで認めていても安全にはなりません。開示はスパイと隠蔽送信を誠実なものと区別するためのみに使用されます。
- 同じファイルでSTEALING判定の外部送信部分として既に判断された送信は、隠蔽送信として二重にカウントされません。
- キャプチャの「開示」は、SKILL.md/README.md内の平文の単語(スクリーンショット、キーストローク、マイク、Webカメラ、ブラウザ履歴など)と照合して種別ごとに確認されます。キャプチャを行いそれを明示しているパックは、認識した上で受け入れるべき機能であり、スパイではありません。
- 外部送信の構成要素は、コメントを含むすべての行からファイルごとに収集されます(保守的:コメントの近くにあるからといって機能の証拠を却下しません)。衛生チェック(shell=True、eval、download-execなど)は完全な行コメントをスキップします。パターンに言及したコメントはドキュメントでありコードではありません。
ルールテーブル
| ルール | 深刻度 | 基準 |
|---|---|---|
MISSING_SKILL_MD | ERROR | パックルートにSKILL.mdがない(大文字小文字が異なる場合は SKILL_MD_CASE(WARN)となり、そのファイルが使用される)。 |
FRONTMATTER_MISSING | ERROR | SKILL.mdに --- ブロックがない。 |
FRONTMATTER_PARSE | ERROR | サポート対象外のfrontmatter行(下記参照)。該当行が引用される。 |
REQUIRED_FIELD | ERROR | name または description が欠落または空。 |
NAME_DIR_MISMATCH | WARN | 正規化されたfrontmatter nameとフォルダ名が一致しない。 |
NAME_FORMAT | WARN | 名前が小文字のケバブケース(kebab-case)ではない。 |
BROAD_TOOL_GRANT | WARN | allowed-tools エントリに *、Tool(*) ワイルドカード、または裸の Bash がある。 Bash(npm run *) のようなスコープ付きの形式は対象外。 |
BROKEN_REFERENCE | ERROR | SKILL.md(マークダウンリンクまたはバックティックパス)またはスクリプト(パスリテラル)から参照されているローカルファイルが存在しない。解決は参照元ファイルのフォルダ、次にパックルートを試行する。 |
REFERENCE_OUTSIDE_PACK | WARN | パックフォルダ外に解決される参照。 |
LARGE_FILE | WARN | 1 MiB(1,048,576 バイト)を超えるファイル。 |
BUNDLED_BINARY | WARN | バイナリファイル(既知のバイナリ拡張子、または最初の8 KiBにNULバイトがある)。バイナリは静的に検証できない。 |
SYMLINK_OUT | INFO | ターゲットがパック外に出るシンボリックリンク。ターゲットはスキャンされない。 |
DANGER_STEALING | ERROR, danger | 上記の組み合わせテーブル。 |
DANGER_SPYING | ERROR, danger | 上記の組み合わせテーブル。キャプチャ種別:画面、キーボード、音声、カメラ、履歴(1ファイル内での履歴ストア読み取り+データベース読み取り)。 |
DANGER_HIDDEN_SENDING | ERROR, danger | 上記の組み合わせテーブル。 |
SECRET_ACCESS | WARN | 認証情報ストア/環境シークレット読み取り、同じファイルに外部送信なし。シークレットソース:.ssh / キーファイル、.aws、.gnupg、.netrc、保存された認証情報ファイル、ブラウザストアとプロファイルフォルダ、.env ファイル、シークレットを名指しする環境アクセス(TOKEN / SECRET / PASSWORD / API_KEY / …)、環境全体の読み取り。 |
UNDISCLOSED_NETWORK | WARN | エンドポイントホストがSKILL.mdにもREADME.mdにも現れないネットワーク呼び出し。ホスト(またはその親ドメイン)がドキュメント内でURLとして現れる場合、開示されたと見なされる。 |
DYNAMIC_ENDPOINT | WARN | ファイル内にリテラルURLが1つもないネットワーク呼び出し。 |
ENCODED_PAYLOAD | WARN | エンコーダの出力が開示されたエンドポイントへの送信に到達する。「到達」は、エンコーダ呼び出しが送信の呼び出しセグメント内にある、またはエンコーダから代入された変数がそのセグメントで使用されていることによって判断される。 |
DISCLOSED_CAPTURE | WARN | キャプチャ + 保存/送信、種別ごとに開示あり。 |
CAPTURE_CAPABILITY | WARN | キャプチャAPI、ファイル内に保存や送信なし。 |
HYGIENE_SHELL_TRUE | WARN | コード行に shell=True / shell: true。 |
HYGIENE_DYNAMIC_EXEC | WARN | コード行に eval( / exec( / os.system( / os.popen( / __import__(。 |
HYGIENE_DOWNLOAD_EXEC | WARN | シェルにパイプされたダウンロード(`curl … |
HYGIENE_OBFUSCATION | WARN | テキストファイル内のbase64ブロブ(120文字以上、大文字小文字混在+数字または +/)、hexブロブ(120文字以上)、または8個以上の \xNN エスケープの連続。ファイルごとに種類ごとに1つの検出。 |
CONCEALED_UNICODE | WARN | テキストファイル内の不可視文字(ゼロ幅、単語結合子、ソフトハイフン、双方向制御文字、Unicodeタグ文字)。カウント、最初の行、文字名が引用される。先頭のBOMはシグネチャであり隠蔽ではないため無視される。 |
CONCEALED_BLANK_RUN | WARN | マークダウンファイル内の50行以上の連続した空白行。その後ろにコンテンツがある場合。 |
HIDDEN_COMMENT | WARN | マークダウンファイル内の120文字以上のHTMLコメント。 |
WRITES_OUTSIDE_PACK | WARN | スクリプトが絶対パス、ホーム、またはシステムパス(/tmp、/etc、~/、$HOME、…)に書き込む。 |
INSTALL_HOOK | WARN | インストール時に実行されるファイル:setup.py、install.* / setup.sh、.pth ファイル、または preinstall/install/postinstall フックを持つ package.json。 |
判定:BLOCKED = 少なくとも1つの危険(danger)検出 → exit 1。REVIEW = 危険なし、ただし少なくとも1つのERRORまたはWARNあり → exit 0(--strict で exit 1)。CLEAN = ERRORまたはWARNなし(INFOは残ってもよい)→ exit 0。REVIEWは意図的にexit 0としています。REVIEWは「人間が読むべき」を意味し、インストールをゲートするスクリプトは警告ではなく危険で失敗すべきです。--strict は異なる意見を持つ人のために存在します。
サポートされるfrontmatter形式
パーサーはスキルパックが実際に使用するfrontmatterの形状を読み取ります:key: value スカラー(引用符は除去)、key: [a, b] インラインリスト、key: に続く - item ブロックリスト、および前のスカラーに折りたたまれるインデントされた継続行。これは意図的に完全なYAMLパーサーではありません。サポート対象外の行は FRONTMATTER_PARSE エラーとなり、その行が引用されます。vetは推測ではなく、読み取れないものを報告します。
スキャン範囲
- パック内のすべてのファイルがサイズとともに一覧化されます。
.gitおよび__pycache__ディレクトリはスキップされます。 - テキストスキャンはスクリプト(拡張子またはシバンによる)、マークダウン、およびその他のテキストファイルを対象とし、ファイルごとに最大2 MiBまでスキャンします。バイナリファイルおよびパック外へのシンボリックリンクターゲットは一覧化されますが、スキャンはされません。
- 参照はSKILL.mdおよびスクリプトファイルから収集されます。他のマークダウンファイル内の参照(references/*.md がさらにリンクするなど)はv1.0.0では追跡されません。
- 開示の判断は、パックルートのSKILL.mdとREADME.mdのみに対して行われます。これはパックをインストールする人が読むことが期待される2つのドキュメントです。
JSONスキーマ(--json)
1つのオブジェクト:
tool、version、commandpack:dir(渡された通り)、dirname、name(frontmatter name または null)、skill_filefiles[]:path、bytes、kind(script|markdown|text|binary|other)、binary、scanned、symlink_outfindings[]:rule、severity(ERROR|WARN|INFO)、danger(bool)、file(または null)、line(または null)、message、fixsummary:findings、errors、warnings、info、danger—findingsと正確に一致するカウントverdict(CLEAN|REVIEW|BLOCKED)、verdict_rule、limits
検出結果は決定論的にソートされます:危険(danger)が最初、次に深刻度、ファイル、行、ルールの順。同じパックは常に同じレポートを生成します。
意図的な非目標(正直に)
- 何も実行しません。 スクリプトの実行、インポート、コンパイル、シェル解析は行われません。ペイロードのデコードも行われません(エンコードされたブロブは報告されますが、開かれません)。
- 静的パターンは証拠であり、証明ではありません。 無害な部品から実行時に動作を組み立てるパック、組み合わせを2つのファイルに分割するパック(vetはファイルごとに組み合わせを判定します)、または平易で正直な文章でソーシャルエンジニアリングを記述するパックは通過する可能性があります。CLEAN判定はパターンが発火しなかったことを意味します。READMEにそう記載されており、すべてのレポートも同様です。
- バイナリは対象外です。 バンドルされたバイナリは、vetがそれについて何も言えないため、正確にフラグ付けされます。
- テレメトリなし、ネットワークなし、書き込みなし。 標準ライブラリのみを使用し、ソースコードにはネットワークやサブプロセスのコードは一切含まれません(テストがインポートを解析して証明します)。
- パターンテーブルはスナップショットです。 新しいキャプチャライブラリ、新しい認証情報ストア、新しいクライアントAPIは常に登場します。ソース内のテーブルはリリース日時点のものであり、完全とは見なされません。