Google製OSV-ScannerをMCPサーバーとして使える「OSV-Scanner-MCP」の v0.17.0 をnpmで公開しました。
前回のv0.16.0で.NET(NuGet)に対応しました。
今回は PHP(Composerのcomposer.lock) を加えました。
脆弱性のスキャン(scan_project)に加えて、修正版の推奨(suggest_fix)にも対応しています。
使い方は変わりません
scan_project・suggest_fixにプロジェクトのディレクトリ(またはcomposer.lock・composer.json)を渡すと、composer.lockも他の言語のlockfileと一緒に検出してスキャンします。
{
"project_path": "/absolute/path/to/php-app"
}
-
packages(本番の依存)とpackages-dev(開発用の依存)の両方を対象にします。開発用の依存にはdependency_groups: ["dev"]が付きます - ComposerもPHPのコードも実行しません。 lockfileを読むだけです
-
composer.lockの無いcomposer.jsonは、coverage.lockfile_missingに生成方法の案内付きで示します。vendorディレクトリは走査しません
composer.lockはそのまま渡さない
composer.lockには、パッケージの名前と版のほかに、取得元のURL、コミットID、スクリプトなどが含まれます。非公開のリポジトリを使っていれば、そのURLも入ります。
OSV-Scanner-MCPは元のcomposer.lockをosv-scannerに渡しません。
安全に読み込んだうえで、パッケージの名前とリリースの版だけを書いたコピーをスキャンします。URL・コミットID・スクリプト・認証情報は、osv-scannerにも照会先にも渡りません。
コピーは次のような形です。
{
"packages": [{ "name": "symfony/http-kernel", "version": "v5.4.1" }],
"packages-dev": [{ "name": "phpunit/phpunit", "version": "9.5.0" }]
}
osv-scanner 2.7.0と2.4.0のどちらでも、このコピーを元のファイルと同じように読むことを確かめました。Symfonyのようなv付きの版も、OSVでは付けない場合と同じ結果になります。
自分のパッケージ(pathリポジトリ)は照会しない
monorepoでは、自分のパッケージをpathリポジトリで参照することがあります。composer.lockには次のように記録されます。
{ "name": "guzzlehttp/psr7", "version": "1.8.1", "dist": { "type": "path", "url": "packages/psr7" } }
osv-scannerはこれもPackagistのパッケージとして照会します。 試しに、公開パッケージと同じ名前・版(guzzlehttp/psr7 1.8.1)のローカルのパッケージを置くと、中身は自分のコードなのに脆弱性が6件報告されました。また、社内向けの名前(例: acme/internal-billing)もapi.osv.devに送られます。Rustのローカルのcrateや、.NETの自分のプロジェクトと同じ問題です。
そこで、dist.typeがpathのパッケージは照会も送信もせず、数だけをcoverage.local_composer_packagesに示します。
{
"coverage": {
"complete": true,
"local_composer_packages": 2,
"skipped_files": []
}
}
自分のコードなので、completeには影響させません。そのパッケージが依存する第三者のパッケージはcomposer.lockに載っているので、通常どおりスキャンされます。
リリースの版だけを照会する
dev-mainや1.x-devのようなブランチの版、エイリアス(1.0 as 2.0)などは、リリースではないので照会しません。理由とともにcoverage.skipped_filesに示し、complete: falseになります。
{
"skipped_files": [
{
"path": "composer.lock",
"reason": "3 entries in packages were not scanned: invalid package names or non-release versions (branches, aliases, and dev versions are not evaluated)"
}
]
}
修正版の推奨(suggest_fix)
Composerの版の順序(1〜4個の数字、v接頭辞、alpha・beta・RC・stable・patchとその短縮形)に合わせて比較し、現在のリリース系列にできるだけ近い修正版を推奨します。
| パッケージ | 現在 | 推奨 | 距離 |
|---|---|---|---|
symfony/http-kernel |
v5.4.1 | 5.4.20 |
same_minor(同じ5.4系) |
guzzlehttp/psr7 |
1.8.1 | 2.12.3 |
cross_major(1.x系では一部の脆弱性が修正されていないため) |
推奨版はOSVに照会し直し、別の既知の脆弱性が無いことも確かめます(candidate_check)。update_hintでは、composer.jsonの制約を更新し、信頼できる環境でcomposer update vendor/package --with-all-dependencies --no-scripts --no-pluginsでlockfileを作り直す方法を案内します。更新の前に、PHPと拡張モジュールの要件も確認してください。
比較できない版の境界を持つアドバイザリでは、修正版を「確認済み」として推奨しません。
実物のcomposer.lockで確かめました
公開リポジトリの実物のlockfileで、osv-scannerが元のファイルから読むパッケージと、本サーバーが照会するパッケージを比べました。
| リポジトリ | osv-scanner(元のファイル) | 本サーバー | 差 |
|---|---|---|---|
| phpmyadmin/phpmyadmin | 137 | 137 | なし |
| matomo-org/matomo | 87 | 83 |
dev-masterの4件(意図して除外) |
| firefly-iii/firefly-iii | 186 | 185 |
dev-mainの1件(意図して除外) |
意図して除外したブランチの版以外は完全に一致し、検出結果も同じでした。
通信先とパッケージの取得元について
Composerのスキャンで通信するのは api.osv.devだけ です。
送るのはパッケージの名前とリリースの版で、pathのパッケージは送りません。
ただし、lockfileだけでは、パッケージがPackagistから来たのかを証明できません。 そのため、非公開のリポジトリ(Private Packagist・Satis・VCSリポジトリなど)のパッケージの名前と版も送られます。公開パッケージと同じ名前の非公開パッケージは、誤検知になることがあります。
Packagistのパッケージには、通常"notification-url": "https://packagist.org/downloads/"が記録されます。これが無いエントリがあれば、coverage.composer_warningsで知らせます(目安であって、取得元の証明ではありません)。
導入
Node.js 20.19以上が必要です。Claude Codeの場合:
claude mcp add osv-scanner -- npx -y osv-scanner-mcp
既に使っている方は、npx -y osv-scanner-mcpであれば次の起動時に最新版になります(@0.16.0のように版を固定している場合は更新してください)。Claude Desktop・Codex CLI・VS Code(GitHub Copilot)・Antigravityの設定例はREADMEのSetupにあります。
設定後は、例えば次のように依頼できます。
/absolute/path/to/my-laravel-appの依存の脆弱性をsuggest_fixで調べて、修正版と更新方法を教えてください。開発用の依存は分けてください。
注意点と今後
-
検出0件は安全の保証ではありません。 必ず
coverageを確認してください -
coverage.completeは、lockfileに載っているエントリを調べられたかを表します。lockfileがcomposer.jsonと食い違っていないか(古くないか)、PHPの版や拡張モジュールの要件は確かめません - Composerのパッケージの
dependency_relation(直接・推移的の区別)は、今はunknownです - .NET(NuGet)の
suggest_fixは引き続き準備中です
まとめ
OSV-Scanner-MCPがPHPのプロジェクトにも使えるようになりました。
composer.lockをそのまま渡すと、自分のパッケージが公開パッケージと取り違えられ、取得元のURLなども含まれます。名前とリリースの版だけを照会し、確かめられなかったものはcoverageで隠さずに返すことを重視しました。
不具合や改善案はGitHub Issuesでお知らせください。