osv-scanner-mcp 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,40 +5,42 @@
5
5
  [![license](https://img.shields.io/npm/l/osv-scanner-mcp)](LICENSE)
6
6
  [![node](https://img.shields.io/node/v/osv-scanner-mcp)](package.json)
7
7
 
8
- Google製 [OSV-Scanner](https://github.com/google/osv-scanner) をラップするMCPサーバーです。Claude等のMCPクライアントから「このプロジェクトの脆弱性をチェックして」と自然言語で依頼するだけで、依存ライブラリの既知の脆弱性(CVE / GHSA)を深刻度順のレポートで取得できます。
8
+ An MCP server that wraps Google's [OSV-Scanner](https://github.com/google/osv-scanner). Ask an MCP client such as Claude to "check this project for vulnerabilities", and it returns the known vulnerabilities (CVE / GHSA) in your dependencies as a report sorted by severity, together with recommended upgrades.
9
9
 
10
- > **ステータス**: [npmで公開中](https://www.npmjs.com/package/osv-scanner-mcp)(`npx -y osv-scanner-mcp`)。Java(Maven / Gradle)、JavaScript(npm / yarn / pnpm / bun)、Python(Poetry / uv / Pipenv / PDM / requirements.txt)、Go のlockfileに対応しています(修正版の推奨も4言語に対応)。MCPクライアントは Claude Code / Claude Desktop / Codex CLI / Antigravity / VS Code(GitHub Copilot)での利用手順を用意しています。
10
+ > **Status**: [Published on npm](https://www.npmjs.com/package/osv-scanner-mcp) (`npx -y osv-scanner-mcp`). Supports lockfiles and manifests for Java (Maven / Gradle), JavaScript (npm / yarn / pnpm / bun), Python (Poetry / uv / Pipenv / PDM / requirements.txt), and Go, with upgrade recommendations for all four. Setup instructions are provided for Claude Code, Claude Desktop, Codex CLI, Antigravity, and VS Code (GitHub Copilot).
11
11
 
12
- ## 特徴
12
+ ## Features
13
13
 
14
- - **複数言語のワンショットスキャン**: `scan_project` ツールにプロジェクトパスを渡すだけで、Java・JavaScript・Python・Goのlockfileを検出してまとめてスキャンします。lockfileが無い・バージョンが未固定などでスキャンできなかった依存は、応答先頭の `coverage` で明示します
15
- - **Javaプロジェクトのスキャン**: `scan_java_project` ツールでJava(Maven / Gradle)のマニフェストだけを対象に、検出→スキャン→整形済みレポートまで一気に返します
16
- - **JAR/WAR実体スキャン**: `scan_java_artifact` ツールで、lockfileが無い・shaded/fat JARしか手元にないプロジェクトでもアーカイブ内メタデータから既知の脆弱性を検出します(ベストエフォート同定であることを明示するcoverage情報付き)
17
- - **SBOM入力スキャン**: `scan_sbom` ツールでCycloneDX/SPDXのJSON SBOMに記録された依存を検査します。SBOMの網羅性や実成果物との一致は未検証であることを明示します
18
- - **深刻度順のレポート**: パッケージごとに脆弱性をCVSSスコア順に整理し、5段階の深刻度ラベル(critical / high / medium / low / unknown)とサマリ集計付きで返します
19
- - **修正版の提示**: 各脆弱性の `fixed_versions` を含めます。MavenはMavenバージョン優先順位規則(`2.17.1-RELEASE` のようなsemver非対応の表記にも対応)、npm・GoはSemantic Versioningの優先順位で正しくソートします
20
- - **セキュリティ第一の設計**: シェル非経由の実行・引数ホワイトリスト・パス正規化と境界チェック・タイムアウト/出力サイズ上限を実装段階から組み込んでいます
14
+ - **One-shot multi-language scan**: Pass a project path to `scan_project`, and it detects and scans the Java, JavaScript, Python, and Go lockfiles in the project together. Dependencies that could not be scanned (for example, a manifest without a lockfile or an unpinned requirement) are reported up front in `coverage`
15
+ - **Upgrade recommendations**: `suggest_fix` recommends, for each vulnerable package, the upgrade closest to the current release line that fixes all its known vulnerabilities, for Maven, npm, PyPI, and Go. The recommended version is also checked against the OSV database so that it does not introduce other known vulnerabilities
16
+ - **Direct and transitive dependencies**: Packages are marked as direct or transitive dependencies (from `package-lock.json`, `go.mod`, `requirements.txt`, and `pom.xml`), and update hints are tailored accordingly, for example by naming the direct dependency that pulls in a transitive one
17
+ - **Java project scan**: `scan_java_project` scans only the Java (Maven / Gradle) manifests and returns a formatted report
18
+ - **JAR/WAR scan**: `scan_java_artifact` detects known vulnerabilities from the metadata inside JAR/WAR archives, for projects without a lockfile or with only shaded/fat JARs (best-effort identification, stated explicitly in `coverage`)
19
+ - **SBOM scan**: `scan_sbom` checks the dependencies recorded in a CycloneDX/SPDX JSON SBOM. It states explicitly that the SBOM's completeness and its match with the actual artifacts are not verified
20
+ - **Severity-sorted reports**: Vulnerabilities are grouped by package and sorted by CVSS score, with five severity labels (critical / high / medium / low / unknown) and summary counts
21
+ - **Fixed versions**: Each vulnerability includes `fixed_versions`, sorted correctly by Maven version precedence (including non-semver forms such as `2.17.1-RELEASE`), Semantic Versioning precedence for npm and Go, and PEP 440 for PyPI
22
+ - **Security first**: No shell execution, a fixed argument allowlist, path normalization and boundary checks, scanning private copies instead of the original files, and timeouts and output size limits are built in
21
23
 
22
- ## 動作要件
24
+ ## Requirements
23
25
 
24
26
  - Node.js >= 20.19
25
- - [OSV-Scanner](https://google.github.io/osv-scanner/) バイナリ — **手動インストールは不要です**。見つからない場合、公式GitHub Releasesからピン留めバージョンを自動ダウンロードし、パッケージに埋め込まれたSHA256チェックサムで検証してから使用します(`~/.cache/osv-scanner-mcp/` にキャッシュ)
26
- - 手動インストール済みのバイナリ(PATH上または `OSV_SCANNER_PATH` 指定)があればそちらを優先します
27
- - 自動ダウンロードを無効化する場合は `OSV_MCP_AUTO_DOWNLOAD=0`
28
- - PATH上のバイナリを使わず常に検証済み自動ダウンロードを使う場合は `OSV_MCP_PREFER_DOWNLOAD=1`(運用環境向け)
29
- - スキャン時と `explain_vulnerability` 実行時にネットワークアクセスが発生します。照会先はOSVデータベース(`api.osv.dev`)ですが、**`pom.xml` のスキャンでは推移的依存を解決するため deps.dev(`api.deps.dev`)にも接続します**。詳細と無効化の方法は[通信先とプライバシー](#通信先とプライバシー)を参照してください
27
+ - The [OSV-Scanner](https://google.github.io/osv-scanner/) binary — **no manual installation needed**. If it is not found, a pinned version is downloaded from the official GitHub Releases and verified against a SHA256 checksum embedded in the package before use (cached in `~/.cache/osv-scanner-mcp/`)
28
+ - A manually installed binary (on `PATH` or set with `OSV_SCANNER_PATH`) is used first
29
+ - Set `OSV_MCP_AUTO_DOWNLOAD=0` to disable the automatic download
30
+ - Set `OSV_MCP_PREFER_DOWNLOAD=1` to always use the verified downloaded binary instead of one on `PATH` (recommended for production)
31
+ - Scans, `suggest_fix`, and `explain_vulnerability` access the network. Vulnerabilities are looked up in the OSV database (`api.osv.dev`), and **scanning `pom.xml` or `requirements.txt` also connects to deps.dev (`api.deps.dev`) to resolve transitive dependencies**. See [Network destinations and privacy](#network-destinations-and-privacy) for details and how to turn this off
30
32
 
31
- ## セットアップ
33
+ ## Setup
32
34
 
33
- ### Claude Code への登録
35
+ ### Claude Code
34
36
 
35
37
  ```bash
36
38
  claude mcp add osv-scanner -- npx -y osv-scanner-mcp
37
39
  ```
38
40
 
39
- ### Claude Desktop への登録
41
+ ### Claude Desktop
40
42
 
41
- `claude_desktop_config.json` に追加:
43
+ Add to `claude_desktop_config.json`:
42
44
 
43
45
  ```json
44
46
  {
@@ -51,27 +53,27 @@ claude mcp add osv-scanner -- npx -y osv-scanner-mcp
51
53
  }
52
54
  ```
53
55
 
54
- ### Codex CLI への登録
56
+ ### Codex CLI
55
57
 
56
58
  ```bash
57
59
  codex mcp add osv-scanner -- npx -y osv-scanner-mcp
58
60
  ```
59
61
 
60
- または `~/.codex/config.toml` に追加:
62
+ Or add to `~/.codex/config.toml`:
61
63
 
62
64
  ```toml
63
65
  [mcp_servers.osv-scanner]
64
66
  command = "npx"
65
67
  args = ["-y", "osv-scanner-mcp"]
66
- startup_timeout_sec = 60 # 初回のnpxパッケージ取得に備えて延長
67
- tool_timeout_sec = 300 # 既定60秒。バイナリ自動ダウンロード+スキャン(既定120秒)を見込んで延長
68
+ startup_timeout_sec = 60 # allow time for the first npx package download
69
+ tool_timeout_sec = 300 # default is 60 seconds; allow for the binary download plus a scan (120 seconds by default)
68
70
  ```
69
71
 
70
- > **注意**: CodexのMCPツール実行タイムアウトは既定60秒です。本サーバーはスキャンのタイムアウトが既定120秒のため、初回のOSV-Scanner自動ダウンロードや大きめのプロジェクトのスキャンでは既定値のままだとCodex側が先にタイムアウトします。上記のように `tool_timeout_sec` の延長を推奨します。
72
+ > **Note**: Codex's MCP tool timeout defaults to 60 seconds, while this server's scan timeout defaults to 120 seconds. With the default, Codex may time out first on the first run (which downloads OSV-Scanner) or on larger projects. Raising `tool_timeout_sec` as above is recommended.
71
73
 
72
- ### Antigravity への登録
74
+ ### Antigravity
73
75
 
74
- エージェントパネルの **MCP Servers → Manage MCP Servers → View raw config** で開く `mcp_config.json` に追加(Claude Desktopと同じ形式):
76
+ Open **MCP Servers → Manage MCP Servers → View raw config** in the agent panel and add to `mcp_config.json` (same format as Claude Desktop):
75
77
 
76
78
  ```json
77
79
  {
@@ -84,13 +86,13 @@ tool_timeout_sec = 300 # 既定60秒。バイナリ自動ダウンロード+
84
86
  }
85
87
  ```
86
88
 
87
- ### VS Code(GitHub Copilot)への登録
89
+ ### VS Code (GitHub Copilot)
88
90
 
89
91
  ```bash
90
92
  code --add-mcp '{"name":"osv-scanner","command":"npx","args":["-y","osv-scanner-mcp"]}'
91
93
  ```
92
94
 
93
- またはワークスペースの `.vscode/mcp.json` に追加(コマンドパレットの **MCP: Add Server** からも設定可能):
95
+ Or add to the workspace's `.vscode/mcp.json` (also available from **MCP: Add Server** in the Command Palette):
94
96
 
95
97
  ```json
96
98
  {
@@ -104,41 +106,41 @@ code --add-mcp '{"name":"osv-scanner","command":"npx","args":["-y","osv-scanner-
104
106
  }
105
107
  ```
106
108
 
107
- ### ソースから使う場合
109
+ ### From source
108
110
 
109
111
  ```bash
110
112
  git clone https://github.com/tedorigawa001/OSV-Scanner-MCP.git
111
113
  cd OSV-Scanner-MCP
112
114
  npm install
113
115
  npm run build
114
- # 登録時は `npx -y osv-scanner-mcp` の代わりに `node /path/to/OSV-Scanner-MCP/dist/index.js` を指定
116
+ # When registering, use `node /path/to/OSV-Scanner-MCP/dist/index.js` instead of `npx -y osv-scanner-mcp`
115
117
  ```
116
118
 
117
- ### 環境変数
119
+ ### Environment variables
118
120
 
119
- | 変数 | 説明 |
121
+ | Variable | Description |
120
122
  |---|---|
121
- | `OSV_SCANNER_PATH` | 使用するosv-scannerバイナリの明示指定。省略時はPATH→自動ダウンロードの順で解決。**指定が無効な場合はフォールバックせずエラーになります**(意図しないバイナリの実行防止) |
122
- | `OSV_MCP_ALLOWED_ROOT` | 指定時、このディレクトリ配下以外のスキャンを拒否します(パストラバーサル対策の境界)。**設定を推奨**。空文字・空白のみは未設定として扱います |
123
- | `OSV_MCP_REQUIRE_ALLOWED_ROOT` | `1` または `true` 指定時、`OSV_MCP_ALLOWED_ROOT` が未設定ならサーバーの起動自体を拒否します(運用環境向けのfail-closedモード) |
124
- | `OSV_MCP_MAX_CONCURRENT_SCANS` | 同時実行できるスキャン数の上限(デフォルト `2`、最大 `16`)。超過したリクエストは待たずに即時エラーになります |
125
- | `OSV_MCP_AUTO_DOWNLOAD` | `0` または `false` でバイナリの自動ダウンロードを無効化(デフォルト有効) |
126
- | `OSV_MCP_PREFER_DOWNLOAD` | `1` または `true` 指定時、PATH上のosv-scannerを使わず、チェックサム検証済みの自動ダウンロードバイナリを常に使用します(PATH汚染による偽バイナリ実行の防止。`OSV_SCANNER_PATH` の明示指定は引き続き最優先) |
127
- | `OSV_MCP_NO_CANDIDATE_CHECK` | `1` または `true` 指定時、`suggest_fix` の推奨先のOSV照会を行いません(応答の `candidate_check` は `disabled`。推奨先に、現在の版には該当しない既知の脆弱性がないことは確認されません) |
128
- | `OSV_MCP_NO_REMOTE_RESOLUTION` | `1` または `true` 指定時、`pom.xml` と `requirements.txt` の推移的依存を deps.dev で解決しません。**止まるのは deps.dev への送信だけで、脆弱性照会のためパッケージの名前とバージョンは引き続き `api.osv.dev` に送られます**。推移的依存の脆弱性は検出できなくなり、その旨が応答の `dependency_resolution.warning` に示されます。詳細は[通信先とプライバシー](#通信先とプライバシー) |
129
-
130
- > **推奨**: `OSV_MCP_ALLOWED_ROOT` は未設定でも動作しますが、その場合は任意の絶対パスをスキャンできてしまいます。悪意ある指示(プロンプトインジェクション)経由で意図しないディレクトリをスキャンさせられる経路を塞ぐため、プロジェクト置き場のルート(例: `~/projects`)を設定しておくことを推奨します。各クライアントの設定で `"env": {"OSV_MCP_ALLOWED_ROOT": "/Users/you/projects"}` のように渡せます(Codex CLIのTOMLでは `[mcp_servers.osv-scanner.env]` セクション)。
131
-
132
- > **本番運用の推奨構成**: 共有サーバーやCI等の運用環境では、次の3つをセットで設定してください。
133
- > - `OSV_MCP_ALLOWED_ROOT=/スキャン対象のルート` — スキャン範囲の境界を固定
134
- > - `OSV_MCP_REQUIRE_ALLOWED_ROOT=1` — 境界未設定なら起動を拒否(fail-closed)
135
- > - `OSV_SCANNER_PATH=/管理者所有の絶対パス` または `OSV_MCP_PREFER_DOWNLOAD=1` — PATH解決に依存せず、実行するバイナリを固定
123
+ | `OSV_SCANNER_PATH` | Explicit path to the osv-scanner binary. If unset, `PATH` is searched, then the binary is downloaded automatically. **If the path is invalid, the server fails instead of falling back** (to avoid running an unintended binary) |
124
+ | `OSV_MCP_ALLOWED_ROOT` | If set, scans outside this directory are refused (the boundary against path traversal). **Recommended.** An empty or whitespace-only value is treated as unset |
125
+ | `OSV_MCP_REQUIRE_ALLOWED_ROOT` | If `1` or `true`, the server refuses to start when `OSV_MCP_ALLOWED_ROOT` is not set (fail-closed mode for production) |
126
+ | `OSV_MCP_MAX_CONCURRENT_SCANS` | Maximum number of concurrent scans (default `2`, maximum `16`). Requests beyond the limit fail immediately instead of waiting |
127
+ | `OSV_MCP_AUTO_DOWNLOAD` | `0` or `false` disables the automatic binary download (enabled by default) |
128
+ | `OSV_MCP_PREFER_DOWNLOAD` | If `1` or `true`, always use the checksum-verified downloaded binary instead of osv-scanner on `PATH` (protects against a fake binary planted on `PATH`; an explicit `OSV_SCANNER_PATH` still takes precedence) |
129
+ | `OSV_MCP_NO_CANDIDATE_CHECK` | If `1` or `true`, `suggest_fix` does not query OSV about recommended versions (`candidate_check` is `disabled`, and recommended versions are not checked for known vulnerabilities that do not affect the current version) |
130
+ | `OSV_MCP_NO_REMOTE_RESOLUTION` | If `1` or `true`, transitive dependencies of `pom.xml` and `requirements.txt` are not resolved through deps.dev. **This stops only the requests to deps.dev; package names and versions are still sent to `api.osv.dev` for the vulnerability lookup.** Vulnerabilities in transitive dependencies are then not detected, and responses say so in `dependency_resolution.warning`. See [Network destinations and privacy](#network-destinations-and-privacy) |
131
+
132
+ > **Recommendation**: The server works without `OSV_MCP_ALLOWED_ROOT`, but then any absolute path can be scanned. To prevent malicious instructions (prompt injection) from scanning unintended directories, set it to the root of your projects (for example `~/projects`). Pass it in the client configuration, for example `"env": {"OSV_MCP_ALLOWED_ROOT": "/Users/you/projects"}` (in Codex CLI's TOML, use a `[mcp_servers.osv-scanner.env]` section).
133
+
134
+ > **Recommended production configuration**: On shared servers, CI, and other production environments, set all three of the following:
135
+ > - `OSV_MCP_ALLOWED_ROOT=/root/of/scan/targets` — fixes the scan boundary
136
+ > - `OSV_MCP_REQUIRE_ALLOWED_ROOT=1` — refuses to start without a boundary (fail-closed)
137
+ > - `OSV_SCANNER_PATH=/absolute/path/owned/by/an/administrator` or `OSV_MCP_PREFER_DOWNLOAD=1` — fixes which binary is run, independent of `PATH`
136
138
  >
137
- > 依存の情報をどこに送るかは[通信先とプライバシー](#通信先とプライバシー)を確認してください。どの設定でも、脆弱性照会のためパッケージの名前とバージョンは `api.osv.dev` に送られます。
139
+ > Check [Network destinations and privacy](#network-destinations-and-privacy) for where dependency information is sent. In every configuration, package names and versions are sent to `api.osv.dev` for the vulnerability lookup.
138
140
 
139
- ### 権限を絞って起動する
141
+ ### Running with restricted permissions
140
142
 
141
- 多層防御として、Nodeの権限モデル(`--permission`)でサーバーが読み書きできる範囲を絞れます(任意。既定の起動方法は変わりません)。`npx` ではNodeのフラグを渡せないため、`node` で直接起動します。
143
+ As an additional layer of defense, you can limit what the server can read and write with Node's permission model (`--permission`). This is optional and does not change the default way of starting the server. `--permission` is available in Node 22.13, 23.5, and later (Node 20's experimental `--experimental-permission` has not been tested). Since `npx` cannot pass Node flags, start the server with `node` directly:
142
144
 
143
145
  ```json
144
146
  {
@@ -165,57 +167,57 @@ npm run build
165
167
  }
166
168
  ```
167
169
 
168
- - 読み取り: サーバー本体(`dist` と `node_modules` を含むディレクトリ)、スキャン対象(`OSV_MCP_ALLOWED_ROOT`)、一時ディレクトリ、osv-scannerのバイナリ
169
- - 一時ディレクトリ(`os.tmpdir()`、macOSでは `$TMPDIR`)は、**シンボリックリンクの解決前と解決後の両方のパス**に読み取りの許可が必要です(macOSの `/var/folders/...` は `/private/var/folders/...` へのリンク)。書き込みは解決後のパスに許可します
170
- - 自動ダウンロードを使う場合は、キャッシュ(`$XDG_CACHE_HOME/osv-scanner-mcp`、既定は `~/.cache/osv-scanner-mcp`)の読み書きも許可します。使わない場合は `OSV_SCANNER_PATH` を指定します
171
- - osv-scannerを起動するため `--allow-child-process` が必要です。**子プロセスのosv-scannerは権限モデルの制限を受けません**(Node自身もこのフラグは権限モデルを弱めると警告します)。osv-scannerには検証済みのコピーだけを渡しているため影響は限定的ですが、より強い隔離が必要ならコンテナ等のOSレベルの仕組みを併用してください
172
- - 必要な許可が欠けている場合は起動時に標準エラー出力へ警告し、スキャン時は `permission_denied`(不足している許可と対象のパス)を返します
170
+ - Read access: the server itself (the directory containing `dist` and `node_modules`), the scan targets (`OSV_MCP_ALLOWED_ROOT`), the temporary directory, and the osv-scanner binary
171
+ - The temporary directory (`os.tmpdir()`, `$TMPDIR` on macOS) needs read access under **both the symlinked and the resolved path** (on macOS, `/var/folders/...` is a symbolic link to `/private/var/folders/...`). Write access is needed on the resolved path
172
+ - If you use the automatic download, also allow reading and writing the cache (`$XDG_CACHE_HOME/osv-scanner-mcp`, by default `~/.cache/osv-scanner-mcp`). Otherwise, set `OSV_SCANNER_PATH`
173
+ - `--allow-child-process` is required to run osv-scanner. **osv-scanner runs as a child process and is not restricted by the permission model** (Node itself warns that this flag weakens the permission model). The impact is limited because osv-scanner only receives verified private copies, but use an OS-level mechanism such as a container if you need stronger isolation
174
+ - If a required permission is missing, the server prints a warning to stderr at startup, and scans return `permission_denied` (naming the missing permission and the path)
173
175
 
174
- ### 通信先とプライバシー
176
+ ### Network destinations and privacy
175
177
 
176
- osv-scanner v2.4.0 で接続先を実機確認した結果です(2026-10-07)。
178
+ Destinations confirmed with osv-scanner v2.4.0 (2026-10-07):
177
179
 
178
- | 操作 | 接続先 | 送られる情報 |
180
+ | Operation | Destinations | Information sent |
179
181
  |---|---|---|
180
- | `pom.xml` のスキャン(`scan_project` / `scan_java_project` / `suggest_fix`) | `api.osv.dev`、**`api.deps.dev`** | パッケージの名前とバージョン。deps.dev には推移的依存の解決のため、`pom.xml` に宣言された依存(社内パッケージを含む)の名前とバージョンが送られます |
181
- | `requirements.txt` のスキャン(`scan_project` / `suggest_fix`) | `api.osv.dev`、**`api.deps.dev`** | `pom.xml` と同じく、推移的依存の解決のため記載された依存の名前とバージョンが deps.dev に送られます。`--index-url` 等に書かれた取得先へは接続しません |
182
- | lockfileのスキャン(`gradle.lockfile`、`package-lock.json` 等のnpm系、`poetry.lock` 等のPython系、`go.mod`) | `api.osv.dev` | パッケージの名前とバージョン(lockfileに全依存が記載済みのため、解決のための外部接続はしません) |
183
- | `scan_java_artifact` / `scan_sbom` | `api.osv.dev` | 同定できたパッケージの名前とバージョン |
184
- | `suggest_fix` の推奨先の照会 | `api.osv.dev` | 推奨を出したパッケージの名前(スキャンで照会済みのもの)と、推奨候補の版(公開されている修正版)。`OSV_MCP_NO_CANDIDATE_CHECK=1` で無効化できます |
185
- | `explain_vulnerability` | `api.osv.dev` | 指定した脆弱性ID |
186
- | バイナリの自動ダウンロード(初回のみ) | GitHub(公式Releases) | なし(ピン留めしたバージョンのバイナリを取得) |
182
+ | Scanning `pom.xml` (`scan_project` / `scan_java_project` / `suggest_fix`) | `api.osv.dev`, **`api.deps.dev`** | Package names and versions. To resolve transitive dependencies, the names and versions of the dependencies declared in `pom.xml` (including internal packages) are sent to deps.dev |
183
+ | Scanning `requirements.txt` (`scan_project` / `suggest_fix`) | `api.osv.dev`, **`api.deps.dev`** | As with `pom.xml`, the names and versions of the listed dependencies are sent to deps.dev to resolve transitive dependencies. Package indexes given with `--index-url` and similar options are not contacted |
184
+ | Scanning lockfiles (`gradle.lockfile`, npm lockfiles such as `package-lock.json`, Python lockfiles such as `poetry.lock`, `go.mod`) | `api.osv.dev` | Package names and versions (lockfiles already list every dependency, so nothing is resolved remotely) |
185
+ | `scan_java_artifact` / `scan_sbom` | `api.osv.dev` | Names and versions of the identified packages |
186
+ | `suggest_fix` checking recommended versions | `api.osv.dev` | The names of packages with a recommendation (already sent during the scan) and the candidate versions (published fixed versions). Disable with `OSV_MCP_NO_CANDIDATE_CHECK=1` |
187
+ | `explain_vulnerability` | `api.osv.dev` | The vulnerability ID |
188
+ | Automatic binary download (first run only) | GitHub (official Releases) | Nothing (downloads the pinned binary) |
187
189
 
188
- api.osv.dev と deps.dev はどちらも Google が運営するサービスです。**どの設定でも、スキャンしたパッケージの名前とバージョンは脆弱性照会のため `api.osv.dev` に送られます**(オフラインでの照会には対応していません)。
190
+ Both api.osv.dev and deps.dev are operated by Google. **In every configuration, the names and versions of scanned packages are sent to `api.osv.dev` for the vulnerability lookup** (offline lookup is not supported).
189
191
 
190
- - **deps.dev への送信を止めたい場合**: `OSV_MCP_NO_REMOTE_RESOLUTION=1` を設定すると、`pom.xml` と `requirements.txt` の推移的依存を解決しなくなり、接続先は `api.osv.dev` だけになります。止まるのは deps.dev への送信だけで、OSV への送信は続きます。また直接書いた依存しかスキャンされず、**推移的依存の脆弱性を見落とします**。この状態は `scan_project` / `scan_java_project` / `suggest_fix` の応答の `dependency_resolution` に `transitive_resolution: "disabled"` と警告で示されるので、検出0件と区別できます。推移的依存も含めて deps.dev を使わずにスキャンするには、lockfile方式(`gradle.lockfile`、`poetry.lock` 等)を使ってください
191
- - **任意の取得先には接続しません**: osv-scanner の `--data-source native` モードは、スキャン対象の `pom.xml` の `<repositories>` に書かれた任意のURLへ接続します(悪意あるpom.xmlで攻撃者のサーバーへ通信させられる)。本サーバーはこのモードを使わず、`deps.dev` を明示指定しています
192
+ - **To stop sending data to deps.dev**: Set `OSV_MCP_NO_REMOTE_RESOLUTION=1`. Transitive dependencies of `pom.xml` and `requirements.txt` are then not resolved, and only `api.osv.dev` is contacted. This stops only the requests to deps.dev; requests to OSV continue. Only the dependencies written in those files are scanned, so **vulnerabilities in transitive dependencies are missed**. Responses of `scan_project` / `scan_java_project` / `suggest_fix` show this as `transitive_resolution: "disabled"` in `dependency_resolution` with a warning, so it can be told apart from zero findings. To scan transitive dependencies without deps.dev, use lockfiles (`gradle.lockfile`, `poetry.lock`, and so on)
193
+ - **Arbitrary repositories are never contacted**: osv-scanner's `--data-source native` mode connects to any URL listed in `<repositories>` of the scanned `pom.xml` (a malicious `pom.xml` could make it contact an attacker's server). This server never uses that mode and sets `deps.dev` explicitly
192
194
 
193
- ## 提供ツール
195
+ ## Tools
194
196
 
195
197
  ### `scan_project`
196
198
 
197
- プロジェクト内のlockfile・マニフェストを検出し、Java / JavaScript / Python / Go の依存をまとめてスキャンします。パッケージマネージャーやビルドは実行しません。
199
+ Detects the lockfiles and manifests in a project and scans the Java / JavaScript / Python / Go dependencies together. Package managers and builds are never run.
198
200
 
199
- **入力**
201
+ **Input**
200
202
 
201
- | パラメータ | 型 | 説明 |
203
+ | Parameter | Type | Description |
202
204
  |---|---|---|
203
- | `project_path` | string | スキャン対象のプロジェクトディレクトリ、または対応するlockfile・マニフェストの絶対パス(直接指定したファイルはそれ1件だけをスキャン) |
205
+ | `project_path` | string | Absolute path to the project directory, or to a supported lockfile or manifest (a file given directly is the only file scanned) |
204
206
 
205
- **対応ファイル**
207
+ **Supported files**
206
208
 
207
- | エコシステム | ファイル |
209
+ | Ecosystem | Files |
208
210
  |---|---|
209
- | Java(Maven) | `pom.xml`、`gradle.lockfile`、`buildscript-gradle.lockfile` |
210
- | JavaScript(npm) | `package-lock.json`、`npm-shrinkwrap.json`、`yarn.lock`、`pnpm-lock.yaml`、`bun.lock`(テキスト形式) |
211
- | Python(PyPI) | `poetry.lock`、`uv.lock`、`Pipfile.lock`、`pdm.lock`、`requirements.txt`(`requirements-dev.txt` 等も) |
211
+ | Java (Maven) | `pom.xml`, `gradle.lockfile`, `buildscript-gradle.lockfile` |
212
+ | JavaScript (npm) | `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lock` (text format) |
213
+ | Python (PyPI) | `poetry.lock`, `uv.lock`, `Pipfile.lock`, `pdm.lock`, `requirements.txt` (and variants such as `requirements-dev.txt`) |
212
214
  | Go | `go.mod` |
213
215
 
214
- `.git`、`node_modules`、`target`、`build`、`.venv`、`venv`、`site-packages`、`__pycache__`、`.tox`、`vendor` とシンボリックリンクは探索しません。検出したファイルだけを形式を明示してOSV-Scannerに渡します(応答の `coverage.manifests` がそのままスキャン範囲です)。探索上限は `scan_java_project` と同じです。
216
+ `.git`, `node_modules`, `target`, `build`, `.idea`, `.vscode`, `.venv`, `venv`, `site-packages`, `__pycache__`, `.tox`, `vendor`, and symbolic links are not searched. Only the detected files are passed to OSV-Scanner, each with its format given explicitly (`coverage.manifests` in the response is exactly the scan scope). The search limits are the same as for `scan_java_project`.
215
217
 
216
- **requirements.txtは元のファイルをOSV-Scannerに渡しません**。本サーバーが解析し、解釈できた依存の行だけを `名前==版` 等の単純な形に直して専用の一時コピーに書き、それをスキャンします(スキャン後に削除)。OSV-Scannerは取り込み指定を独自に解釈してたどる(`- r ../x.txt` のような空白入りも取り込みとみなし、スキャン範囲の外のファイルを読む)ため、コピーには取り込み指定やオプションを一切含めません。取り込み(`-r` / `--requirement`)は、プロジェクトディレクトリ内の取り込み先だけを本サーバーが展開してコピーに含めます。
218
+ **`requirements.txt` files are not passed to OSV-Scanner as they are.** The server parses them, rewrites only the dependency lines it can interpret into simple forms such as `name==version`, and scans a private temporary copy (deleted after the scan). OSV-Scanner interprets include directives on its own (it even treats `- r ../x.txt`, with a space, as an include and reads files outside the scan scope), so the copy never contains include directives or options. Includes (`-r` / `--requirement`) are expanded by the server, and only when the included file is inside the project directory.
217
219
 
218
- **出力の読み方**
220
+ **Reading the output**
219
221
 
220
222
  ```json
221
223
  {
@@ -223,13 +225,13 @@ api.osv.dev と deps.dev はどちらも Google が運営するサービスで
223
225
  "dependency_resolution": { "transitive_resolution": "enabled" },
224
226
  "coverage": {
225
227
  "complete": false,
226
- "warning": "一部の依存はスキャンされていないか、版を推測してスキャンしています(…)",
228
+ "warning": "…",
227
229
  "manifests": [{ "path": "web/package-lock.json", "ecosystem": "npm", "format": "package-lock.json" }],
228
- "lockfile_missing": [{ "path": "svc/package.json", "ecosystem": "npm", "status": "missing", "hint": "lockfileがありません。…" }],
230
+ "lockfile_missing": [{ "path": "svc/package.json", "ecosystem": "npm", "status": "missing", "hint": "…" }],
229
231
  "unpinned_requirements": [{ "file": "py/requirements.txt", "line": 2, "name": "Jinja2", "specifier": ">=2.0", "kind": "lower_bound" }],
230
232
  "unscannable_requirements": [
231
- { "file": "py/requirements.txt", "line": 4, "text": "-e git+https://…", "reason": "編集可能インストール(-e)はスキャンされません" },
232
- { "file": "py/requirements.txt", "line": 5, "text": "-r ../shared/base.txt", "reason": "取り込み先がプロジェクトディレクトリの外のため展開しません" }
233
+ { "file": "py/requirements.txt", "line": 4, "text": "-e git+https://…", "reason": "…" },
234
+ { "file": "py/requirements.txt", "line": 5, "text": "-r ../shared/base.txt", "reason": "…" }
233
235
  ],
234
236
  "skipped_files": []
235
237
  },
@@ -244,53 +246,53 @@ api.osv.dev と deps.dev はどちらも Google が運営するサービスで
244
246
  }
245
247
  ```
246
248
 
247
- - **`coverage` を必ず確認してください**。`complete: false` の場合、一部の依存はスキャンされていないため、検出0件でも安全とは言えません
248
- - `lockfile_missing`: lockfileの無いマニフェスト(`package.json`、`pyproject.toml`、`Pipfile`、`setup.py`、`build.gradle` 等)。同じディレクトリに同じエコシステムのlockfileがあれば記録しません。上位のディレクトリのlockfileだけがある場合は、`package-lock.json`(v2以降)にそのディレクトリが収録されていることを確認できたときだけ記録しません(npm workspaces)。収録されていなければ `status: "missing"`、確認できない形式(yarn.lock、Python系等)なら `status: "unconfirmed"` として記録します。`hint` の手順でlockfileを生成してから再スキャンしてください(生成は信頼できる環境で)
249
- - `unpinned_requirements`: requirements.txtのうち、版を固定していない行。`kind` は `unpinned`(版の指定なし)・`range`(`>`、`<`、`!=`、`==1.*`、範囲の組み合わせ等)・`lower_bound`(`>=`、`~=`)。`unpinned` と `range` の行はOSV-Scannerがスキャンせず、`lower_bound` の行は下限の版を使用中の版とみなしてスキャンします(該当パッケージには `version_is_lower_bound: true` が付き、実際の版とは異なる可能性があります)
250
- - `unscannable_requirements`: スキャンされない行と理由。`-e`、`name @ URL`、パス指定、展開しなかった取り込み(プロジェクトディレクトリの外・存在しない・URL・上限超過)、制約ファイル(`-c`、適用しません)、解釈できないオプションや版の指定。解釈できない行は無視せず、ここに記録します
251
- - `skipped_files`: スキャン対象から外したファイルと理由(requirements.txt自体が読めない・1MiBを超える場合、`pom.xml` の親POMが許可ルートの外を参照する場合)。親POMを読めず、親POMを含めずにスキャンした `pom.xml` もここに理由付きで示します([親POMの扱い](#親pomの扱い)を参照)
252
- - 各一覧は200件までで、超えた分の件数を `omitted_items` に返します
253
- - `ecosystem_breakdown` は、脆弱性0件のエコシステムも含めて「スキャンした」ことを示します
254
- - `dependency_relation` は直接依存(`direct`)か推移的依存(`transitive`)かを示します。OSV-Scannerの出力にはこの区別がないため、本サーバーがスキャンしたファイルのコピーを解析して判定します:
255
- - `package-lock.json`(v2以降): ルートとworkspaceのpackage.jsonの依存を、Nodeの解決規則(入れ子の `node_modules` から上位へ)で解決したものが直接依存、そこからたどれるものが推移的依存です。直接依存には宣言しているpackage.jsonを `declared_in` に、推移的依存にはそれを要求している直接依存の名前を `introduced_by`(最大10件、超えた分は `introduced_by_omitted`)に示します。直接依存でもあり他の依存からも要求される版は `direct` とし、`introduced_by` も付けます
256
- - `go.mod`: `// indirect` の無い `require` が直接依存です。`replace` で置き換えているモジュールには `replaced_in_go_mod: true` を付けます(OSV-Scannerは置換先のパスと版で報告します)
257
- - `requirements.txt`: ファイルに書かれた依存が直接依存、deps.devで解決された依存が推移的依存です
258
- - `pom.xml`: OSV-Scannerは、`pom.xml`(と親POM)に宣言された依存と、deps.devで解決された推移的依存を別々の結果(`source.type` が `lockfile` / `unknown`)に分けて報告するため、それで判定します(親POM・プロファイル・プロパティ・依存管理の解釈はOSV-Scannerと同じになります)。`introduced_by` / `declared_in` は付きません。この判定はOSV-Scannerの文書化されていない出力の形に依存するため、想定外の形の場合は `unknown` にします
259
- - 上記以外の形式(`gradle.lockfile`、`yarn.lock`、`pnpm-lock.yaml`、`bun.lock`、`poetry.lock`、`uv.lock`、`Pipfile.lock`、`pdm.lock`)と、lockfileVersion 1・どこからも要求されていないエントリは `unknown` です。複数のlockfileで判定が異なる場合は `mixed` です
260
- - `dependency_groups` はOSV-Scannerが付けた依存グループ(例: `dev`)の生の値です。lockfileの形式によって欠落・不正確なため(pnpmでは付かず、pdmでは `optional` になる等)、参考情報として扱ってください
261
- - 修正版の推奨(`suggest_fix`)はJava・JavaScript・Python・Goに対応しています
249
+ - **Always check `coverage`.** If `complete` is `false`, some dependencies were not scanned, so zero findings does not mean the project is safe
250
+ - `lockfile_missing`: manifests without a lockfile (`package.json`, `pyproject.toml`, `Pipfile`, `setup.py`, `build.gradle`, and so on). Not recorded if a lockfile of the same ecosystem is in the same directory. If there is only a lockfile in a parent directory, the manifest is not recorded only when `package-lock.json` (v2 or later) is confirmed to contain that directory (npm workspaces). Otherwise it is recorded with `status: "missing"`, or `status: "unconfirmed"` for formats that cannot be checked (yarn.lock, Python lockfiles, and so on). Generate the lockfile as described in `hint` (in a trusted environment) and scan again
251
+ - `unpinned_requirements`: lines in `requirements.txt` that do not pin a version. `kind` is `unpinned` (no version), `range` (`>`, `<`, `!=`, `==1.*`, combined ranges, and so on), or `lower_bound` (`>=`, `~=`). OSV-Scanner does not scan `unpinned` and `range` lines, and scans `lower_bound` lines at the lower bound (those packages are marked `version_is_lower_bound: true` and may differ from the installed version)
252
+ - `unscannable_requirements`: lines that are not scanned, with the reason: `-e`, `name @ URL`, paths, includes that were not expanded (outside the project directory, missing, URLs, or over the limits), constraint files (`-c`, not applied), and options or version specifiers that cannot be interpreted. Lines that cannot be interpreted are recorded here instead of being ignored
253
+ - `skipped_files`: files excluded from the scan, with the reason (a `requirements.txt` that cannot be read or is larger than 1 MiB, or a `pom.xml` whose parent POM chain references a file outside the allowed root). A `pom.xml` scanned without its parent POM, because the parent could not be read, is also listed here with the reason (see [Parent POMs](#parent-poms))
254
+ - Each list holds up to 200 entries; the number of omitted entries is returned in `omitted_items`
255
+ - `ecosystem_breakdown` includes ecosystems with zero findings, to show that they were scanned
256
+ - `dependency_relation` shows whether a package is a direct (`direct`) or transitive (`transitive`) dependency. OSV-Scanner does not report this, so the server determines it by parsing the scanned copies:
257
+ - `package-lock.json` (v2 or later): dependencies of the root and workspace `package.json` files, resolved with Node's lookup rules (nested `node_modules` first, then parent directories), are direct; everything reachable from them is transitive. Direct dependencies list the `package.json` files that declare them in `declared_in`; transitive dependencies list the direct dependencies that require them in `introduced_by` (up to 10, with the rest counted in `introduced_by_omitted`). A version that is both a direct dependency and required by another dependency is `direct` and also has `introduced_by`
258
+ - `go.mod`: `require` lines without `// indirect` are direct. Modules affected by a `replace` directive are marked `replaced_in_go_mod: true` (OSV-Scanner reports the replacement module and version)
259
+ - `requirements.txt`: dependencies written in the file are direct; dependencies resolved through deps.dev are transitive
260
+ - `pom.xml`: OSV-Scanner reports the dependencies declared in `pom.xml` (and its parent POMs) and the transitive dependencies resolved through deps.dev as separate results (`source.type` `lockfile` / `unknown`), and this split is used (so parent POMs, profiles, properties, and dependency management are interpreted exactly as OSV-Scanner does). `introduced_by` / `declared_in` are not available. This relies on undocumented OSV-Scanner output, so anything unexpected is reported as `unknown`
261
+ - Other formats (`gradle.lockfile`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lock`, `poetry.lock`, `uv.lock`, `Pipfile.lock`, `pdm.lock`), lockfile version 1, and entries not reachable from the project are `unknown`. If lockfiles disagree, the value is `mixed`
262
+ - `dependency_groups` is the raw dependency group reported by OSV-Scanner (for example `dev`). It is missing or inaccurate for some lockfile formats (absent for pnpm, `optional` for pdm, and so on), so treat it as informational
263
+ - Upgrade recommendations (`suggest_fix`) are available for Java, JavaScript, Python, and Go
262
264
 
263
265
  ### `scan_java_project`
264
266
 
265
- Java(Maven)プロジェクトをスキャンし、既知の脆弱性レポートを返します。
267
+ Scans a Java (Maven) project and returns a known-vulnerability report.
266
268
 
267
- **入力**
269
+ **Input**
268
270
 
269
- | パラメータ | 型 | 説明 |
271
+ | Parameter | Type | Description |
270
272
  |---|---|---|
271
- | `project_path` | string | スキャン対象のプロジェクトディレクトリ、または pom.xml / gradle.lockfile の絶対パス |
273
+ | `project_path` | string | Absolute path to the project directory, or to a `pom.xml` / `gradle.lockfile` |
272
274
 
273
- > **Gradleプロジェクトについて**: 本ツールは**lockfile方式**のみ対応です(ビルド実行方式は build.gradle の任意コード実行を伴うため、セキュリティ上の理由から採用していません)。`gradle.lockfile` が無い場合は `./gradlew dependencies --write-locks` で生成してください(依存ロック未設定の場合は `build.gradle` に `dependencyLocking { lockAllConfigurations() }` の追加が必要です)。
275
+ > **Gradle projects**: Only the **lockfile approach** is supported (running the build would execute arbitrary code in `build.gradle`, so it is not used for security reasons). If there is no `gradle.lockfile`, generate one with `./gradlew dependencies --write-locks` (if dependency locking is not configured, add `dependencyLocking { lockAllConfigurations() }` to `build.gradle`).
274
276
 
275
- > **スキャン範囲**: ディレクトリを指定すると、配下の `pom.xml` / `gradle.lockfile` / `buildscript-gradle.lockfile` を深さに関係なく検出し、**検出したファイルだけ**をスキャンします(応答の `manifests` がそのままスキャン範囲です)。同じディレクトリにある `package-lock.json` や `requirements.txt` などJava以外のファイルはスキャンしません。`.git`、`node_modules`、`target`、`build`、`.idea`、`.vscode` とシンボリックリンクは探索しません。探索するエントリが20万件、またはマニフェストが1,000件を超える場合は、結果を黙って省略せず `manifest_search_limit_exceeded` を返します。`pom.xml` などのマニフェストを直接指定した場合は、ディレクトリを探索せず**そのファイルだけ**をスキャンします(上限に達した場合の回避手段としても使えます)。
277
+ > **Scan scope**: For a directory, every `pom.xml` / `gradle.lockfile` / `buildscript-gradle.lockfile` below it is detected regardless of depth, and **only the detected files** are scanned (`manifests` in the response is exactly the scan scope). Non-Java files in the same directories, such as `package-lock.json` and `requirements.txt`, are not scanned. `.git`, `node_modules`, `target`, `build`, `.idea`, `.vscode`, and symbolic links are not searched. If the search visits more than 200,000 entries or finds more than 1,000 manifests, `manifest_search_limit_exceeded` is returned instead of silently truncating the results. When a manifest such as `pom.xml` is given directly, the directory is not searched and **only that file** is scanned (also useful as a workaround when the limits are reached).
276
278
 
277
- #### 親POMの扱い
279
+ #### Parent POMs
278
280
 
279
- OSV-Scannerは `pom.xml` の `<parent>` が参照する親POM(`<relativePath>` の指すファイル。省略時はMavenの既定どおり `../pom.xml`)を読み、親の親もたどって、そこに書かれた依存を結果に含めます。サブモジュールだけをスキャンしても親から引き継いだ依存を検出できるのはこのためです。
281
+ OSV-Scanner reads the parent POM referenced by `<parent>` in `pom.xml` (the file at `<relativePath>`, or `../pom.xml` by default as in Maven), follows the chain to its own parents, and includes the dependencies declared there. This is why scanning a submodule alone still detects the dependencies it inherits.
280
282
 
281
- `OSV_MCP_ALLOWED_ROOT` を設定している場合、親POMの連鎖のどこかが**許可ルートの外**のファイルを参照する `pom.xml` は、スキャン対象から外します(許可ルート外のファイルの内容を結果や照会先に出さないため)。外したファイルは応答の `skipped_manifests`(`scan_project` では `coverage.skipped_files`)に理由付きで示し、`scope_warning` で「検出0件でも安全とは判断しない」旨を伝えます。全件が外れた場合や、該当する `pom.xml` を直接指定した場合は `path_outside_allowed_root` を返します。
283
+ When `OSV_MCP_ALLOWED_ROOT` is set, a `pom.xml` whose parent POM chain references a file **outside the allowed root** at any point is excluded from the scan (so that the contents of files outside the allowed root never reach the results or the lookup services). Excluded files are listed with the reason in `skipped_manifests` (`coverage.skipped_files` in `scan_project`), and `scope_warning` says that zero findings should not be taken as safe. If every manifest is excluded, or such a `pom.xml` is given directly, `path_outside_allowed_root` is returned.
282
284
 
283
- 存在する親POMを読めない場合(10MiBを超える、名前付きパイプ等の通常のファイルでない、末尾がシンボリックリンク等)は、その `pom.xml` を親POMを含めずにスキャンし、親から継承する依存が欠ける可能性を応答の `incomplete_manifests`(`scan_project` では `coverage.skipped_files`、`coverage.complete` は `false`)に理由付きで示します。子の `pom.xml` に依存が無く `no_packages_found` になる場合も、エラーのメッセージに同じ理由を含めます。親POMが存在しない場合(ルートの `pom.xml` で既定の `../pom.xml` が無い等)は、元の配置でもOSV-Scannerは親を読まないため欠落として扱いません。
285
+ If an existing parent POM cannot be read (larger than 10 MiB, not a regular file such as a named pipe, a symbolic link at the final path component, and so on), the `pom.xml` is scanned without it, and the possibly missing inherited dependencies are reported with the reason in `incomplete_manifests` (`coverage.skipped_files` in `scan_project`, with `coverage.complete` set to `false`). If the child `pom.xml` itself declares no dependencies and the scan ends with `no_packages_found`, the error message includes the same reason. A parent POM that does not exist (for example the default `../pom.xml` of a root `pom.xml`) is not reported, because OSV-Scanner would not read it from the original location either.
284
286
 
285
- - 許可ルート内の親POMは従来どおり読みます(サブモジュールのスキャンは許可ルート内なら引き続き使えます)
286
- - `<relativePath/>`(空)はローカルの親POMを参照しないため対象外です
287
- - 親POMの指定は、OSV-Scanner(Go)のXMLの解釈に合わせて読みます。要素は名前空間の接頭辞に関係なく要素名で照合し(`<m:parent>` も親として扱う)、ルート要素の直下の `parent` だけを対象にし、文字参照を展開します
288
- - XMLの仕様どおり、解析前に改行(CRLF・CR)をLFに正規化します
289
- - 同じ解釈を保証できない場合は除外します: ルート直下の `parent` や `relativePath` が複数ある、CDATA・DOCTYPE・未知の実体参照・プロパティ参照(`${...}`)がある、タグが閉じていない、UTF-8として読めない、`relativePath` に制御文字(改行・タブ等)・通常の空白以外の空白・書式文字が含まれる(通常の空白や日本語のディレクトリ名は使えます)
290
- - 親のGAVが一致しなければOSV-Scannerは読みませんが、本サーバーはGAVを確認せず、許可ルートの外に参照先のファイルがあれば安全側に除外します
291
- - `OSV_MCP_ALLOWED_ROOT` が未設定の場合は任意の絶対パスをスキャンできる状態のため、この検証は行いません
287
+ - Parent POMs inside the allowed root are still read (scanning submodules inside the allowed root keeps working)
288
+ - `<relativePath/>` (empty) does not reference a local parent POM and is ignored
289
+ - The parent reference is read the way OSV-Scanner's (Go) XML decoder reads it: elements are matched by local name regardless of namespace prefix (`<m:parent>` counts as a parent), only a `parent` directly under the root element is used, and character references are expanded
290
+ - As the XML specification requires, line endings (CRLF and CR) are normalized to LF before parsing
291
+ - A `pom.xml` is excluded when the same interpretation cannot be guaranteed: multiple `parent` or `relativePath` elements directly under the root, CDATA, a DOCTYPE, unknown entity references, property references (`${...}`), unclosed tags, content that is not valid UTF-8, or a `relativePath` containing control characters (newlines, tabs, and so on), whitespace other than a regular space, or format characters (regular spaces and non-ASCII directory names are allowed)
292
+ - OSV-Scanner does not read a parent whose GAV does not match, but this server does not check the GAV and excludes any existing reference outside the allowed root, to stay on the safe side
293
+ - When `OSV_MCP_ALLOWED_ROOT` is not set, any absolute path can be scanned anyway, so this check is not performed
292
294
 
293
- **出力(成功時)**
295
+ **Output (success)**
294
296
 
295
297
  ```json
296
298
  {
@@ -322,77 +324,77 @@ OSV-Scannerは `pom.xml` の `<parent>` が参照する親POM(`<relativePath>`
322
324
  }
323
325
  ```
324
326
 
325
- - `packages` は最も深刻な脆弱性を持つ順、各 `vulnerabilities` は深刻度順(unknownは末尾)
326
- - `fixed_versions` はOSVに記載された修正版です。MavenはMaven優先順位、npm・GoはSemantic Versioningの優先順位で昇順(SemVerとして解釈できない表記は末尾)、PyPIはPEP 440の優先順位で昇順(v0.5.0以前は記載順)、その他のエコシステムはOSVの記載順のまま(並び順は保証しません)。複数のリリース系統(例: 2.12系バックポートと2.15系)が混在することがあります。プレリリース版(`5.0.0-beta.3`)やGoの疑似バージョン(`0.0.0-20180925071336-cf3bd585ca2a`)が含まれることもあります。空配列は「OSVに修正版の記載がない」ことを意味します。v0.4.1以前はMaven以外のパッケージで常に空配列を返していました
327
- - `severity_score` が取得できない脆弱性は `null` / `"unknown"` として扱います
327
+ - `packages` is sorted by the most severe vulnerability, and each `vulnerabilities` list by severity (unknown last)
328
+ - `fixed_versions` lists the fixed versions recorded in OSV, in ascending order: by Maven precedence for Maven, Semantic Versioning precedence for npm and Go (values that are not valid SemVer come last), and PEP 440 for PyPI (in the order listed by OSV up to v0.5.0); other ecosystems keep the order listed by OSV (the order is not guaranteed). Several release lines may be mixed (for example a 2.12 backport and the 2.15 line). Pre-releases (`5.0.0-beta.3`) and Go pseudo-versions (`0.0.0-20180925071336-cf3bd585ca2a`) may be included. An empty array means that OSV lists no fixed version. Up to v0.4.1, this was always empty for packages outside Maven
329
+ - Vulnerabilities without a severity score are reported as `null` / `"unknown"`
328
330
 
329
331
  ### `scan_java_artifact`
330
332
 
331
- JAR/WARファイルの実体をスキャンします。既存のマニフェスト方式とは別ツールです。
333
+ Scans JAR/WAR archives themselves. This is a separate tool from the manifest-based scans.
332
334
 
333
335
  ```json
334
336
  { "artifact_path": "/absolute/path/to/application.war" }
335
337
  ```
336
338
 
337
- `artifact_path` はJAR/WARファイル、または探索するディレクトリの絶対パスです。
338
- ディレクトリ指定では `target` や `build` も探索します。`.git`、`node_modules`、`.idea`、`.vscode` と探索中のシンボリックリンクは除外します。
339
- 探索上限は深さ8・100ファイル・10,000エントリです。上限に達して探索を完了できない場合は、結果を黙って省略せず `artifact_search_limit_exceeded` を返します。対象を絞って再実行してください。
340
- `OSV_MCP_ALLOWED_ROOT` による制限も適用されます。
339
+ `artifact_path` is the absolute path to a JAR/WAR file, or to a directory to search.
340
+ A directory search includes `target` and `build`, and excludes `.git`, `node_modules`, `.idea`, `.vscode`, and symbolic links.
341
+ The search is limited to a depth of 8, 100 archives, and 10,000 entries. If the search cannot complete within the limits, `artifact_search_limit_exceeded` is returned instead of silently truncating the results; narrow the target and try again.
342
+ `OSV_MCP_ALLOWED_ROOT` applies as well.
341
343
 
342
- OSV-Scanner 2.4.0の `java/archive` プラグインを使用し、ネストJARもスキャナー側で解析します。Javaコードやビルドは実行しません。
343
- 識別にはアーカイブ内メタデータを用いるため、除去済みメタデータやshaded/minimized JAR内の依存を見落とす場合があります。
344
+ OSV-Scanner 2.4.0's `java/archive` plugin is used, and nested JARs are also analyzed by the scanner. No Java code is executed and no build is run.
345
+ Identification relies on metadata inside the archives, so dependencies whose metadata was removed, and dependencies inside shaded/minimized JARs, may be missed.
344
346
 
345
- **出力の読み方:**
347
+ **Reading the output:**
346
348
 
347
- - 先頭の `coverage` に `jars_found`、`jars_identified`、`unidentified_jars` を返します。件数はWARも含む、ファイルシステム上で列挙した外側のアーカイブ単位です。ネストJARの総数ではありません。
348
- - `artifacts[].status` は `identified_with_vulnerabilities` / `identified_without_known_vulnerabilities` / `inferred_only` / `unidentified` の4値です。「同定済み」は少なくとも1件のMaven座標を取得できた意味であり、全依存の同定ではありません。`inferred_only` は推測した座標(下記)だけで同定したアーカイブで、脆弱性が見つかった場合も含め `jars_identified` に数えず、`unidentified_jars` に理由付きで示します(検出件数は `identified_vulnerability_count` に示します。推測の誤ったgroupIdで他の脆弱性を取りこぼしている可能性があるため)。
349
- - **推測した座標**: `pom.properties` を含まないJAR(Spring Frameworkの本体JARなど)について、OSV-Scannerはファイル名等からMaven座標を推測し、groupIdを誤ることがあります(例: `spring-beans:spring-beans`。正しくは `org.springframework:spring-beans`)。誤った座標はOSVで照合されず、**既知の脆弱性を取りこぼします**(実例: zipkin-server 2.23.2 のfat JARに含まれる spring-beans 5.3.2 のSpring4Shell(CVE-2022-22965)は検出されません)。groupIdに `.` を含まない座標を推測とみなし、`coverage.inferred_coordinates`(件数・一覧・警告)と、該当パッケージの `coordinates_inferred: true` で示します。`commons-io:commons-io` のような古い形式の正しい座標も含まれます(安全側)。`.` を含む誤った推測(`com.sun.jna:jna` 等)は区別できません。正確な結果には、ビルド元のlockfile・`pom.xml` を `scan_project` でスキャンしてください
350
- - `coverage.completeness` は常に `incomplete`。`identified_vulnerability_count: 0` は安全性の保証ではありません。
351
- - `packages` は同定できた脆弱なパッケージの詳細です。複数アーカイブに含まれる同一パッケージ・脆弱性は全体集計では重複排除します。
352
- - JAR/WARが無い場合は `no_scannable_artifacts`、全件同定不能の場合は警告を含む成功レポートです。
349
+ - `coverage` comes first, with `jars_found`, `jars_identified`, and `unidentified_jars`. The counts are per outer archive found on the file system (including WARs), not the total number of nested JARs.
350
+ - `artifacts[].status` is one of `identified_with_vulnerabilities` / `identified_without_known_vulnerabilities` / `inferred_only` / `unidentified`. "Identified" means that at least one Maven coordinate was found, not that every dependency was identified. `inferred_only` is an archive identified only through inferred coordinates (see below). Even when vulnerabilities are found for it, it is not counted in `jars_identified` and is listed in `unidentified_jars` with a hint (its findings are shown in `identified_vulnerability_count`), because wrong inferred groupIds may hide other vulnerabilities.
351
+ - **Inferred coordinates**: For JARs without `pom.properties` (such as the main Spring Framework JARs), OSV-Scanner infers the Maven coordinates from file names and similar clues, and often gets the groupId wrong (for example `spring-beans:spring-beans` instead of `org.springframework:spring-beans`). Vulnerabilities are not matched for wrong coordinates, so **known vulnerabilities are missed** (for example, Spring4Shell (CVE-2022-22965) in spring-beans 5.3.2 inside the zipkin-server 2.23.2 fat JAR is not detected). Coordinates whose groupId contains no `.` are treated as inferred and reported in `coverage.inferred_coordinates` (count, items, and a warning), and the affected packages are marked `coordinates_inferred: true`. Correct old-style coordinates such as `commons-io:commons-io` are included as well (erring on the safe side). Wrong inferences that contain a `.` (such as `com.sun.jna:jna`) cannot be detected. For accurate results, scan the build's lockfile or `pom.xml` with `scan_project`
352
+ - `coverage.completeness` is always `incomplete`. `identified_vulnerability_count: 0` does not mean the archives are safe.
353
+ - `packages` lists the vulnerable packages that were identified. The same package and vulnerability found in several archives are counted once in the totals.
354
+ - If no JAR/WAR is found, `no_scannable_artifacts` is returned. If no archive can be identified, a successful report with a warning is returned.
353
355
 
354
- `suggest_fix` は引き続きマニフェスト方式専用です。experimentalプラグインを使うため、OSV-Scannerのピン留めバージョン更新時には、フラグとJAR/WARの出力形式も再検証してください。
355
- 信頼できないアーカイブの展開はOSV-Scannerのネイティブ処理に依存します。タイムアウト・出力上限はありますが、OSレベルのメモリ制限やサンドボックスを提供するものではありません。
356
+ `suggest_fix` remains manifest-based only. Because this tool uses an experimental plugin, the flags and the JAR/WAR output format must be re-verified whenever the pinned OSV-Scanner version is updated.
357
+ Extracting untrusted archives relies on OSV-Scanner's native code. There are timeouts and output limits, but no OS-level memory limit or sandbox is provided.
356
358
 
357
359
  ### `scan_sbom`
358
360
 
359
- 既存のSBOMに記録された依存をOSV-Scannerで照会します。SBOMの生成、ビルド、JARの実行は行いません。
361
+ Looks up the dependencies recorded in an existing SBOM with OSV-Scanner. It does not generate SBOMs, run builds, or execute JARs.
360
362
 
361
363
  ```json
362
364
  { "sbom_path": "/absolute/path/to/release-sbom.json" }
363
365
  ```
364
366
 
365
- - **対応形式**: UTF-8 JSONのCycloneDX 1.4 / 1.5 / 1.6、SPDX 2.2 / 2.3。XML、SPDX tag-value、SPDX 3は未対応です。
366
- - **入力**: 16MiB以下のローカル通常ファイルの絶対パス。ファイル名は任意で、内容から形式を判別します。CycloneDXは`components`、SPDXは`packages`配列が必要です。形式・主要構造の確認であり、仕様全体のJSON Schema検証ではありません。
367
- - **識別情報**: CycloneDXの`components[].purl`、SPDXの`packages[].externalRefs`にバージョン付きPackage URLを含めてください。例: `pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1`。詳細は[OSV-Scanner公式ドキュメント](https://github.com/google/osv-scanner/blob/main/docs/scan-source.md)を参照してください。
368
- - **安全な読み込み**: 許可ルートと読み込み中のサイズ上限を確認し、権限制限付きの一時コピーだけをスキャンします。元ファイルは変更せず、一時コピーは成功・失敗ともに削除します。スキャン中にサーバーが終了した場合(SIGTERM/SIGINT/SIGHUP、MCPクライアントがstdinを閉じた場合)も、一時コピーを削除し実行中のOSV-Scannerを止めてから終了します。
367
+ - **Supported formats**: UTF-8 JSON CycloneDX 1.4 / 1.5 / 1.6 and SPDX 2.2 / 2.3. XML, SPDX tag-value, and SPDX 3 are not supported.
368
+ - **Input**: the absolute path to a local regular file of 16 MiB or less. Any file name is accepted; the format is detected from the content. CycloneDX requires a `components` array and SPDX a `packages` array. Only the format and main structure are checked, not the full JSON Schema.
369
+ - **Identification**: Include versioned Package URLs in CycloneDX `components[].purl` or SPDX `packages[].externalRefs`, for example `pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1`. See the [OSV-Scanner documentation](https://github.com/google/osv-scanner/blob/main/docs/scan-source.md) for details.
370
+ - **Safe reading**: The allowed root and the size limit (enforced while reading) are checked, and only a private temporary copy is scanned. The original file is never modified, and the copy is deleted on success and failure. If the server is terminated during a scan (SIGTERM/SIGINT/SIGHUP, or the MCP client closing stdin), the copy is deleted and the running OSV-Scanner is stopped before exiting.
369
371
 
370
- 出力の先頭に`coverage`を返します。
372
+ `coverage` comes first in the output.
371
373
 
372
- - `identified_package_count`: スキャナーが識別した、名前・バージョン・エコシステムの重複を除いたパッケージ数。既知脆弱性がないものも含みます。
373
- - `unidentified_packages`: スキャナー出力に存在したものの、バージョン等が不足しているパッケージ。スキャナー自体が読み飛ばした項目は列挙できないため、この配列が空でも全件検査を意味しません。
374
- - `status`: 識別できたものがあれば`packages_identified`、なければ`no_packages_identified`。
375
- - `completeness` / `artifact_match`: ともに`not_verified`。SBOMの依存網羅性や、実際のJARと同一ビルドのものかは自動検証しません。
374
+ - `identified_package_count`: the number of distinct packages (by name, version, and ecosystem) identified by the scanner, including those without known vulnerabilities.
375
+ - `unidentified_packages`: packages present in the scanner output but missing a version or other information. Items the scanner itself skipped cannot be listed, so an empty array does not mean everything was checked.
376
+ - `status`: `packages_identified` if anything was identified, otherwise `no_packages_identified`.
377
+ - `completeness` / `artifact_match`: both `not_verified`. Whether the SBOM covers every dependency, and whether it matches the actual build, are not verified.
376
378
 
377
- `sbom`には元ファイルのパス・形式・仕様バージョン・スキャンに用いた入力バイト列のSHA256を返します。`identified_vulnerability_count`と`packages`には識別できた依存の検出結果を返します。**検出0件は「安全」の保証ではありません。** メタデータのないJARを補完するには、そのビルドに対応する正確なSBOMを別途用意してください。
379
+ `sbom` returns the original file path, the format, the specification version, and the SHA256 of the bytes that were scanned. `identified_vulnerability_count` and `packages` contain the findings for the identified dependencies. **Zero findings does not mean the software is safe.** To cover JARs without metadata, prepare an accurate SBOM for that build.
378
380
 
379
- 不正JSONは`invalid_sbom`、未対応形式は`unsupported_sbom_format`、入力上限超過は`sbom_too_large`、存在しない・読み取れないファイルは`sbom_not_found`です。空のSBOMや識別できるパッケージがないSBOMは、警告付きの成功レポートになります。既存ツールと同じタイムアウト・出力上限・同時実行枠を使用します。
381
+ Invalid JSON returns `invalid_sbom`, an unsupported format `unsupported_sbom_format`, input over the size limit `sbom_too_large`, and a missing or unreadable file `sbom_not_found`. An empty SBOM, or one with no identifiable packages, returns a successful report with a warning. The same timeout, output limit, and concurrency limit as the other tools apply.
380
382
 
381
383
  ### `suggest_fix`
382
384
 
383
- `scan_project` と同じ検出・スキャンを実行し、脆弱なパッケージごとに**推奨アップグレードバージョン**を提案します。推奨はJava(Maven / Gradle)・JavaScript(npm)・Python(PyPI)・Goに対応しています。単純な最大バージョンではなく、現在のバージョンに最も近いリリース系統の修正版を3段階フォールバックで選定します:
385
+ Runs the same detection and scan as `scan_project` and recommends an **upgrade version** for each vulnerable package. Recommendations are available for Java (Maven / Gradle), JavaScript (npm), Python (PyPI), and Go. Instead of simply taking the highest fixed version, it picks the fixed version closest to the current release line, falling back through three tiers:
384
386
 
385
- | Tier | 意味 |
387
+ | Tier | Meaning |
386
388
  |---|---|
387
- | `same_minor` | 現在と同じ系統内の修正版(最小の変更で済む) |
388
- | `major_internal` | 同一メジャー内の修正版(マイナーバージョンアップが必要) |
389
- | `cross_major` | メジャーアップグレードが必要(破壊的変更の可能性あり) |
389
+ | `same_minor` | A fixed version in the same release line (the smallest change) |
390
+ | `major_internal` | A fixed version within the same major version (a minor upgrade) |
391
+ | `cross_major` | A major upgrade is needed (may include breaking changes) |
390
392
 
391
- npm・Go・PyPIの「同じ系統」は、npmの `^`(キャレット)が互換とみなす範囲です(PyPIには共通の互換規則がありませんが、0.x系でマイナー更新が破壊的変更になるパッケージがあるため同じ規則で扱います。epochが変わる更新も `cross_major`)。1.0.0以上は Maven と同じく major.minor 単位ですが、0.x では同じ `0.minor` 内だけを同じ系統とし、マイナー更新(`0.3` → `0.4`)は `cross_major`、0.0.x ではどの更新も `cross_major` として扱います(SemVerでは0.xの更新は互換を保証しないため)。
393
+ For npm, Go, and PyPI, the "same release line" is the range npm's caret (`^`) treats as compatible (PyPI has no common compatibility rule, but some 0.x packages make breaking changes in minor releases, so the same rule is used; a change of epoch is also `cross_major`). From 1.0.0 the line is major.minor, as for Maven. For 0.x, only the same `0.minor` is the same line, so a minor update (`0.3` → `0.4`) is `cross_major`, and for 0.0.x every update is `cross_major` (SemVer does not guarantee compatibility for 0.x updates).
392
394
 
393
- **入力**: `scan_project` と同じ(`project_path`)
395
+ **Input**: the same as `scan_project` (`project_path`)
394
396
 
395
- **出力(成功時)**
397
+ **Output (success)**
396
398
 
397
399
  ```json
398
400
  {
@@ -407,126 +409,146 @@ npm・Go・PyPIの「同じ系統」は、npmの `^`(キャレット)が互換
407
409
  "package": "org.apache.logging.log4j:log4j-core",
408
410
  "current_version": "2.14.1",
409
411
  "ecosystem": "Maven",
412
+ "dependency_relation": "direct",
410
413
  "recommended_upgrade": "2.25.4",
411
414
  "upgrade_tier": "major_internal",
412
- "verification": "verified",
413
- "upgrade_note": "取得済みの影響範囲に基づき修正対象CVEの範囲外と確認した候補です",
415
+ "upgrade_note": "…",
416
+ "update_hint": "…",
417
+ "candidate_check": "clean",
414
418
  "per_cve_detail": [
415
- { "id": "GHSA-jfh8-c2jp-5v3q", "cve": "CVE-2021-44228", "severity": "critical", "fixed_in": "2.15.0", "tier": "major_internal" }
416
- ]
419
+ { "id": "GHSA-jfh8-c2jp-5v3q", "cve": "CVE-2021-44228", "severity": "critical", "fixed_in": "2.15.0", "tier": "major_internal", "recommended_status": "not_affected" }
420
+ ],
421
+ "verification": "verified"
417
422
  }
418
423
  ]
419
424
  }
420
425
  ```
421
426
 
422
- - `recommended_upgrade` は既知の修正版を候補に、修正対象の全CVEの影響範囲外と確認できたものを3段階Tier順・バージョン昇順で選びます。CVEごとの修正版の最大値を単純に採用せず、別系統で再び影響を受ける候補も除外します。全公開版の中での最小性や未検出の脆弱性がないことは保証しません。
423
- - OSVの影響範囲(`introduced` / `fixed` / `last_affected` / 上限なし)を照合します。MavenはMavenの優先順位で `ECOSYSTEM` 範囲を、npm・GoはSemantic Versioningの優先順位で `SEMVER` / `ECOSYSTEM` 範囲を、PyPIはPEP 440の優先順位(`1.8c1` や `2.8.0-rc0` のような正規形でない表記も正規化)で `ECOSYSTEM` 範囲を使います。同じエントリに `ECOSYSTEM` 範囲があれば、コミット単位の `GIT` 範囲は無視します。`versions` に明示された影響も確認します(Gitのタグ名など版として解釈できない値は、解釈できる候補と一致しえないため無視します)。範囲欠落・不正・未対応形式(`GIT` 等)・`limit` による不完全な情報や、範囲の境界に解釈できない版(一部のGHSAに残る `19.03.9`、PyTorchの `2.6.0-cu124` のような表記)を含む場合は安全と推定せず、候補を検証できなければ `recommended_upgrade: null`、`verification: "no_verified_candidate"` を返します。
424
- - プレリリース版(`5.0.0-beta.3`、`15.6.0-canary.61`、Goの疑似バージョン、PyPIの `rc`・`dev` 版。post版は正式版扱い)は、正式版の候補では全CVEを解消できない場合だけ推奨し、`recommended_is_prerelease: true` を付けます。同じTierのプレリリースより、上のTierの正式版を優先します。
425
- - 推奨時は `verification: "verified"`、CVEごとの `recommended_status` は `affected` / `not_affected` / `unknown` です。推奨保留時は `not_evaluated` になります。`per_cve_detail.fixed_in` は各CVE単独の候補であり、最終推奨先の判定は `recommended_status` を参照してください。
426
- - 現在より新しい修正版候補がないCVEは `tier: "unfixed"` として推奨の修正対象から除外します(情報欠落を含む場合があります)。除外したCVEも推奨先で判定し、その状態を表示します。全CVEがunfixedの場合も `recommended_upgrade` は `null` です。修正版の記載はあるがバージョンとして解釈できないCVE(SemVerでない `13.0` 等)は `tier: "unparseable_fix"` とし、修正版が無いとは扱わず修正対象に残すため、推奨は保留(`no_verified_candidate`)になります。
427
- - npm・Go・PyPIの提案には更新方法の `update_hint` を付けます。PyPIでは、requirements.txtやpyproject.toml・Pipfileの指定を更新してlockfileを再生成し、推移的依存はpipの制約ファイル(`-c`)やuv・Poetryの上書き設定で版を指定します。Maven(`pom.xml` 由来)では、直接依存は `<dependency>` の版(親POM・プロパティ・BOMで管理していればそちら)、推移的依存は `<dependencyManagement>` での上書きを案内します。推移的依存の場合、npmでは要求している直接依存の更新か、ルートの `package.json` の `overrides`(ルートのプロジェクトでのみ有効)で版を指定します。Goでは `go get <module>@<version>` で更新できます。Goのv2以上のメジャーは別のモジュールパス(`/v2` 等)としてOSV上も別パッケージになるため、新しいメジャー系列の修正版は候補に含まれません。現在の版が疑似バージョン(タグのないコミット)の場合は `upgrade_note` に示します。
428
- - **推奨先のOSV照会**: 推奨はスキャンで分かった脆弱性(現在の版に該当するもの)の範囲だけで検証しているため、推奨先に現在の版には該当しない新しい脆弱性がありえます(例: cryptography 3.2 の推奨候補 49.0.0 は、44.0.0 で混入し 50.0.0 で修正された2件に該当)。そこで推奨先を `api.osv.dev` に照会し、該当する脆弱性があれば、それも避けるよう修正版を候補に加えて選び直します(この例では 50.0.0 を推奨し、`upgrade_note` に理由を示します)。結果は `candidate_check` に示します:
429
- - `clean`: 推奨先に該当する既知の脆弱性はありません
430
- - `has_known_vulnerabilities`: 避けられる修正版の候補が見つからず、推奨先が既知の脆弱性に該当します(`recommended_known_vulnerabilities` にID)
431
- - `conflict`: OSVが、スキャンした脆弱性に候補が該当すると返しました(手元の範囲情報との食い違い)。他に候補がないため推奨を保留します(`recommended_upgrade: null`、`verification: "no_verified_candidate"`)
432
- - `failed`: 照会に失敗したか、応答の形式が不正でした(推奨はスキャンした脆弱性に対して検証済みのまま返します)
433
- - `skipped`: 照会回数の上限(1パッケージ4回、1回の呼び出しで合計60回)のため照会していません
434
- - `disabled`: `OSV_MCP_NO_CANDIDATE_CHECK=1` で無効化されています
435
-
436
- 照会するのは推奨を出したパッケージだけで、送るのはスキャンで既に照会したパッケージの名前と、推奨候補の版です。OSVの判定が手元の範囲情報と食い違う候補(スキャンした脆弱性に該当と返る候補)は推奨しません。不正な応答(オブジェクトでない応答・レコード、文字列でないページトークン)は「該当なし」とは扱わず失敗とします。照会で見つかった脆弱性は現在の版の脆弱性ではないため、`per_cve_detail` には含めません。
437
- - 各提案には `scan_project` と同じ `dependency_relation`(と `introduced_by` / `declared_in` / `replaced_in_go_mod`)を付け、`update_hint` を直接/推移的依存の別に応じて具体化します(npmの推移的依存なら `introduced_by` の直接依存の更新と `overrides`、Goの `replace` ならreplaceの版の更新、等)。`unknown` / `mixed` の場合は両方の場合を案内します。
438
- - requirements.txtの `>=X` / `~=X` の行は、OSV-Scannerが下限Xを使用中の版とみなしてスキャンしています。この依存の提案には `version_is_lower_bound: true` を付け、推奨は「下限を推奨版以上に引き上げる」意味であること(実際にインストールされる版とは異なりうること)を `upgrade_note` に示します。
439
- - 推奨に未対応のエコシステム(SBOM由来のRubyGems等)は `verification: "unsupported_ecosystem"`、現在の版をバージョンとして解釈できない場合(npmのgit・ローカルパス依存等)は `verification: "unparseable_version"` を返し、どちらもCVEごとの `tier: "unsupported"` として `unfixed` には数えません(修正版の有無は判定していないため。修正版は `scan_project` の `fixed_versions` や `explain_vulnerability` で確認できます)。
440
- - 応答の `coverage` は `scan_project` と同じです。lockfileの無いマニフェストや外したファイルがあれば `complete: false` になり、それらの依存は提案に含まれません。v0.4.2以前の `skipped_manifests` / `scope_warning` は `coverage.skipped_files` / `coverage.warning` に統合しました。
427
+ - `recommended_upgrade` is chosen from the known fixed versions: the first candidate, in tier order and then ascending version order, that is confirmed to be outside the affected ranges of every vulnerability being fixed. It does not simply take the highest fixed version per CVE, and it excludes candidates that are affected again in another release line. It does not guarantee that the candidate is the smallest among all published versions, or that it has no undetected vulnerabilities.
428
+ - The OSV affected ranges (`introduced` / `fixed` / `last_affected` / open-ended) are checked: `ECOSYSTEM` ranges by Maven precedence for Maven, `SEMVER` / `ECOSYSTEM` ranges by Semantic Versioning precedence for npm and Go, and `ECOSYSTEM` ranges by PEP 440 for PyPI (non-canonical forms such as `1.8c1` and `2.8.0-rc0` are normalized). Events are sorted by version before evaluation, as in the OSV specification's evaluation algorithm. Commit-based `GIT` ranges are ignored when the same entry has an `ECOSYSTEM` range. Versions explicitly listed in `versions` are also checked (values that are not versions, such as Git tag names, are ignored, since they can never equal a valid candidate). If the information is incomplete (missing, malformed, or unsupported ranges such as `GIT`, `limit`, or range boundaries that cannot be parsed, such as `19.03.9` in some GHSAs or PyTorch's `2.6.0-cu124`), no candidate is assumed to be safe; if no candidate can be verified, `recommended_upgrade: null` and `verification: "no_verified_candidate"` are returned.
429
+ - Pre-releases (`5.0.0-beta.3`, `15.6.0-canary.61`, Go pseudo-versions, PyPI `rc` and `dev` versions; post-releases count as stable) are recommended only when no stable candidate fixes every vulnerability, and are marked `recommended_is_prerelease: true`. A stable version in a higher tier is preferred over a pre-release in a lower tier.
430
+ - When a version is recommended, `verification` is `verified`, and each CVE's `recommended_status` is `affected` / `not_affected` / `unknown` (`not_evaluated` when the recommendation is withheld). `per_cve_detail.fixed_in` is the candidate for that CVE alone; see `recommended_status` for the final recommendation.
431
+ - CVEs with no fixed version newer than the current one get `tier: "unfixed"` and are left out of the recommendation (the data may be incomplete). They are still evaluated against the recommended version, and the result is shown. If every CVE is unfixed, `recommended_upgrade` is `null` as well. A CVE whose fixed version is listed but cannot be parsed as a version (such as `13.0`, which is not SemVer) gets `tier: "unparseable_fix"`; it is not treated as unfixed but stays in the set to be fixed, so the recommendation is withheld (`no_verified_candidate`).
432
+ - Suggestions include an `update_hint`, tailored to whether the package is a direct or transitive dependency:
433
+ - Maven (from `pom.xml`): for a direct dependency, update the `<dependency>` version (or the parent POM, property, or BOM that manages it); for a transitive dependency, override the version in `<dependencyManagement>` or update the direct dependency that requires it
434
+ - npm: for a direct dependency, update the version in the `package.json` listed in `declared_in`; for a transitive dependency, update the direct dependency named in `introduced_by`, or set the version with `overrides` in the root `package.json` (effective only in the root project)
435
+ - Go: `go get <module>@<version>` (also for `// indirect` modules). For a module affected by `replace`, update the version in the `replace` directive instead of `require`. Major versions 2 and later use a different module path (`/v2` and so on) and are separate packages in OSV, so fixes in a newer major line are not included as candidates. If the current version is a pseudo-version (an untagged commit), `upgrade_note` says so
436
+ - PyPI: update the version in `requirements.txt`, `pyproject.toml`, or `Pipfile` and regenerate the lockfile; for a transitive dependency, use a pip constraints file (`-c`) or the override settings of uv or Poetry
437
+ - When the relation is `unknown` or `mixed`, both cases are described (no hint is given for Maven packages from `gradle.lockfile`)
438
+ - **Checking recommended versions against OSV**: Recommendations are verified only against the vulnerabilities found in the scan (those affecting the current version), so a recommended version could be affected by newer vulnerabilities (for example, cryptography 3.2's candidate 49.0.0 is affected by two vulnerabilities introduced in 44.0.0 and fixed in 50.0.0). The server therefore queries `api.osv.dev` about the recommended version, and if it is affected, adds those vulnerabilities to the set to be fixed and chooses again with their fixed versions as candidates (50.0.0 in this example, with the reason in `upgrade_note`). The result is reported in `candidate_check`:
439
+ - `clean`: OSV reports no known vulnerabilities for the recommended version
440
+ - `has_known_vulnerabilities`: no candidate avoids them, so the recommended version has known vulnerabilities (IDs in `recommended_known_vulnerabilities`)
441
+ - `conflict`: OSV reports that a candidate is affected by a vulnerability the scan had evaluated as not affecting it (the range data disagree), and no other candidate is available, so the recommendation is withheld (`recommended_upgrade: null`, `verification: "no_verified_candidate"`)
442
+ - `failed`: the query failed or returned a malformed response (the recommendation, verified against the scanned vulnerabilities, is still returned)
443
+ - `skipped`: the query limit was reached (4 queries per package, 60 per call)
444
+ - `disabled`: disabled with `OSV_MCP_NO_CANDIDATE_CHECK=1`
445
+
446
+ Only packages with a recommendation are queried, and only the package name (already sent during the scan) and the candidate version are sent. A candidate on which OSV and the local range data disagree is never recommended. A malformed response (a response or record that is not an object, or a page token that is not a string) is treated as a failure, not as "no vulnerabilities". Vulnerabilities found this way do not affect the current version, so they are not added to `per_cve_detail`.
447
+ - Each suggestion carries the same `dependency_relation` as `scan_project` (and `introduced_by` / `declared_in` / `replaced_in_go_mod`).
448
+ - `requirements.txt` lines with `>=X` / `~=X` are scanned by OSV-Scanner at the lower bound X. Their suggestions are marked `version_is_lower_bound: true`, and `upgrade_note` explains that the recommendation means raising the lower bound to at least the recommended version (the installed version may differ).
449
+ - Ecosystems without recommendation support (such as RubyGems from an SBOM) return `verification: "unsupported_ecosystem"`, and current versions that cannot be parsed (such as npm git or local path dependencies) return `verification: "unparseable_version"`. In both cases each CVE gets `tier: "unsupported"` and is not counted as unfixed (whether a fixed version exists is not evaluated; check `fixed_versions` in `scan_project` or `explain_vulnerability`).
450
+ - `coverage` is the same as in `scan_project`. If a manifest has no lockfile or a file was excluded, `complete` is `false`, and those dependencies are not included in the suggestions. The `skipped_manifests` / `scope_warning` fields of v0.4.2 and earlier were merged into `coverage.skipped_files` / `coverage.warning`.
441
451
 
442
452
  ### `explain_vulnerability`
443
453
 
444
- 指定したGHSA-ID / CVE-IDの脆弱性の詳細を**OSVデータベースAPI(api.osv.dev)から直接取得**して返します(スキャンは実行しません)。スキャン結果の `id` をそのまま渡せます。クライアントLLMの知識カットオフ以降に公開された脆弱性の説明に特に有効です。
454
+ Returns the details of a vulnerability, given its GHSA or CVE ID, **fetched directly from the OSV database API (api.osv.dev)** (no scan is run). IDs from the scan results can be passed as they are. This is especially useful for vulnerabilities published after the client LLM's knowledge cutoff.
445
455
 
446
- **入力**
456
+ **Input**
447
457
 
448
- | パラメータ | 型 | 説明 |
458
+ | Parameter | Type | Description |
449
459
  |---|---|---|
450
- | `vulnerability_id` | string | 脆弱性のID(例: `GHSA-jfh8-c2jp-5v3q`、`CVE-2021-44228`) |
460
+ | `vulnerability_id` | string | The vulnerability ID (for example `GHSA-jfh8-c2jp-5v3q` or `CVE-2021-44228`) |
451
461
 
452
- **出力(成功時)**: `id` / `aliases` / `summary` / `details`(説明markdown、4,000字上限)/ `severity`(CVSSベクトル)/ `published` / `modified` / `affected`(影響パッケージとバージョン範囲)/ `references`(アドバイザリ・修正コミット等のURL、http/httpsのみ・20件上限)
462
+ **Output (success)**: `id` / `aliases` / `summary` / `details` (markdown description, up to 4,000 characters) / `severity` (CVSS vectors) / `published` / `modified` / `affected` (affected packages and version ranges) / `references` (URLs of advisories, fix commits, and so on; http/https only, up to 20)
453
463
 
454
- > **注意**: OSVの正規IDはGHSA等のため、CVE-IDでは見つからない場合があります(その場合はエラーメッセージでGHSA-IDでの照会を案内します)。
464
+ > **Note**: OSV's canonical IDs are GHSA and similar IDs, so a CVE ID may not be found (the error message then suggests querying with the GHSA ID).
455
465
 
456
- **出力(エラー時)** — 全ツール共通
466
+ **Output (error)** — common to all tools
457
467
 
458
- `isError: true` とともに、機械判読可能な `kind` を含むJSONを返します:
468
+ Returns JSON with a machine-readable `kind`, together with `isError: true`:
459
469
 
460
470
  ```json
461
471
  {
462
472
  "error": {
463
473
  "kind": "no_manifest_found",
464
- "message": "対応マニフェスト(pom.xml / gradle.lockfile)が見つかりません: /path/to/project"
474
+ "message": "…"
465
475
  }
466
476
  }
467
477
  ```
468
478
 
469
- | kind | 意味 |
479
+ | kind | Meaning |
470
480
  |---|---|
471
- | `binary_not_found` | OSV-Scannerが見つからない(インストール案内をmessageに含む) |
472
- | `project_not_found` | 指定パスが存在しない・ディレクトリ/pom.xmlでない |
473
- | `permission_denied` | Nodeの権限モデル(`--permission`)でファイルの読み書きが許可されていない(メッセージに不足している許可と対象のパスを示します。[権限を絞って起動する](#権限を絞って起動する)を参照) |
474
- | `no_manifest_found` | 対応マニフェスト(pom.xml / gradle.lockfile)が見つからない |
475
- | `scan_input_too_large` | スキャン対象ファイル(一時ディレクトリへのコピー)の合計サイズが上限(2GiB)を超えた。対象を絞って再実行する |
476
- | `manifest_search_limit_exceeded` | マニフェスト探索が上限(20万エントリ・1,000マニフェスト)に達した。より狭いディレクトリかマニフェストを直接指定する |
477
- | `binary_download_failed` | バイナリのダウンロード失敗(未対応プラットフォーム含む) |
478
- | `binary_checksum_mismatch` | ダウンロードしたバイナリのチェックサム不一致(改ざん/破損の可能性) |
479
- | `gradle_lockfile_missing` | Gradleプロジェクトだがgradle.lockfileが無い(生成手順をmessageで案内) |
480
- | `path_outside_allowed_root` | `OSV_MCP_ALLOWED_ROOT` の外を指している(マニフェストの親POMが許可ルートの外を参照し、スキャンできるマニフェストが残らない場合を含む) |
481
- | `no_packages_found` | スキャン対象パッケージなし(依存関係が未定義のpom.xml等) |
482
- | `scan_failed` | OSV-Scannerが異常終了(stderr抜粋を`detail`に含む) |
483
- | `scan_timeout` | タイムアウト(デフォルト120秒) |
484
- | `too_many_concurrent_scans` | 同時実行スキャン数が上限(デフォルト2)に達している。完了を待って再試行 |
485
- | `output_too_large` | 出力がサイズ上限(デフォルト32MB)を超過 |
486
- | `invalid_output` | 出力がJSONとして解釈できない |
487
- | `invalid_vulnerability_id` | 脆弱性IDの形式が不正 |
488
- | `vulnerability_not_found` | 指定IDの脆弱性がOSVデータベースに存在しない |
489
- | `api_request_failed` | OSV APIへのリクエスト失敗(ネットワーク・タイムアウト・非2xx) |
490
- | `internal_error` | 想定外のエラー(内部情報は返しません) |
491
-
492
- ## セキュリティ設計
493
-
494
- 脆弱性診断ツール自体が攻撃経路にならないよう、以下を実装しています。
495
-
496
- - **サプライチェーン対策**: バイナリの自動ダウンロードは公式GitHub Releasesに限定し、バージョンをピン留め。**パッケージに埋め込まれたSHA256チェックサム**で検証します(配布元のSHA256SUMSファイルは信用しないため、リリース側が改ざんされても検出可能)。検証合格まで実行権限を与えず、キャッシュ済みバイナリも使用のたびに再検証します。`OSV_MCP_PREFER_DOWNLOAD=1` でPATH上の未検証バイナリを使わない運用も選べます
497
- - **コマンドインジェクション対策**: シェルを経由しない `spawn` + 引数配列で実行。OSV-Scannerへの引数は固定リストのみで、可変部は検証済み絶対パス1つだけ
498
- - **スナップショット方式(検査と読み込みの不一致の防止)**: OSV-Scannerには元のファイルを一切渡しません。lockfile・`pom.xml`(親POMの連鎖を含む)・JAR/WARは、本サーバーが安全に1回だけ読んだ内容を専用の一時ディレクトリ(所有者のみアクセス可、終了時に削除)へコピーしてスキャンし、検査もそのコピーに対して行います。検査の後で元のファイルやディレクトリを差し替えても結果には影響しません。親POMは元の配置を一時ディレクトリ内に再現してコピーするため、OSV-Scannerが相対パスで親をたどっても、見つかるのは検証してコピーしたファイルだけです(`..` を重ねて一時ディレクトリの外に届く参照は除外)。読み込みは末尾のシンボリックリンクをたどらず、名前付きパイプ等の通常のファイル以外は読まず(処理が止まらない)、読み終えた後にパスを解決し直して境界の内側かつ開いた実体と同じファイルかを確認します。コピーの合計サイズは2GiBまでです(超えると `scan_input_too_large`)。SIGKILL等の捕捉できない終了で残った一時ディレクトリは、次回以降の起動時に削除します(名前が本サーバーの接頭辞に完全一致し、自分が所有する実体のディレクトリで、最終更新から24時間以上経過したものだけ。シンボリックリンクはたどりません)
499
- - **パストラバーサル対策**: 入力パスは `realpath` でシンボリックリンク解決後に境界チェック。pom.xml探索ではシンボリックリンクを辿りません。OSV-Scannerにはディレクトリを渡さず、検出したマニフェストだけを形式を明示して個別に渡します(ディレクトリを渡すと、OSV-Scannerが同じディレクトリの `requirements.txt` も読み、その取り込み指定 `-r ../x.txt` でスキャン範囲の外のファイルを読むため)。`scan_project` でrequirements.txtをスキャンする場合は元ファイルを渡さず、解釈できた依存の行だけを正規化して書いた専用コピーをスキャンします。コピーには取り込み指定を含めないため、OSV-Scannerの取り込みの解釈と本サーバーの解析がずれても、範囲外のファイルは読まれません。`pom.xml` の親POMの連鎖が `OSV_MCP_ALLOWED_ROOT` の外を参照する場合は、その `pom.xml` をスキャン対象から外します([親POMの扱い](#親pomの扱い))
500
- - **DoS対策**: タイムアウト・stdout上限・stderr抜粋上限を設定。スキャン結果は防御的にパースし、形式不正でも例外を投げません。同時実行スキャン数も上限(デフォルト2)を設け、並列リクエストによるプロセスの無制限起動を防ぎます。本サーバー自身の解析も、同じファイルは1回だけ読んで結果を使い回し(workspaceの収録確認でのlockfile、requirements.txtの共通の取り込み先、親POM)、読む量の合計に上限を設けます
501
- - **fail-closedな運用モード**: `OSV_MCP_REQUIRE_ALLOWED_ROOT=1` で、スキャン許可ルート未設定時にサーバーの起動自体を拒否できます
502
- - **通信先の固定と明示**: osv-scannerの依存解決先は `deps.dev` を明示指定し、スキャン対象のpom.xmlが指定する任意のリポジトリへ接続するモード(`--data-source native`)は使いません(テストで保証)。通信先の一覧と、deps.devへの送信を止める `OSV_MCP_NO_REMOTE_RESOLUTION=1` は[通信先とプライバシー](#通信先とプライバシー)を参照
503
- - **情報漏えい対策**: 想定外の例外はスタックトレース等を含めず `internal_error` に丸めます。外部由来のテキスト(脆弱性summary等)は長さ上限付きの「データ」として構造化して返します
504
- - **プロンプトインジェクション対策**: OSVデータベース由来のテキスト(summary / details / ID等)とOSV-Scannerのstderrは、LLMクライアントへ返す前にサニタイズします。制御文字(ANSIエスケープ含む)・ゼロ幅文字・双方向制御文字(RLO等)・Unicodeタグ文字(不可視のテキスト密輸)・行区切り(U+2028/2029)を除去し、NFC正規化を適用。外部データの読み取りアクセサを単一のサニタイズ境界にすることで適用漏れを防いでいます
505
-
506
- ## 開発
481
+ | `binary_not_found` | OSV-Scanner was not found (the message includes installation instructions) |
482
+ | `project_not_found` | The path does not exist, or is not a directory or a supported file |
483
+ | `permission_denied` | Node's permission model (`--permission`) does not allow the read or write (the message names the missing permission and the path; see [Running with restricted permissions](#running-with-restricted-permissions)) |
484
+ | `no_manifest_found` | No supported lockfile or manifest was found (for `scan_project`, the message includes how to generate missing lockfiles) |
485
+ | `manifest_search_limit_exceeded` | The manifest search reached its limits (200,000 entries or 1,000 manifests). Specify a narrower directory or the manifest itself |
486
+ | `no_scannable_artifacts` | No JAR/WAR archive was found (`scan_java_artifact`) |
487
+ | `artifact_search_limit_exceeded` | The JAR/WAR search reached its limits (depth 8, 100 archives, 10,000 entries). Narrow the target |
488
+ | `scan_input_too_large` | The total size of the files to scan (the copies in the temporary directory) exceeds the limit (2 GiB). Narrow the target |
489
+ | `sbom_not_found` | The SBOM file does not exist, is not a regular file, or cannot be read |
490
+ | `invalid_sbom` | The SBOM is not valid JSON or lacks the required structure |
491
+ | `unsupported_sbom_format` | The SBOM format or version is not supported |
492
+ | `sbom_too_large` | The SBOM exceeds the size limit (16 MiB) |
493
+ | `binary_download_failed` | The binary download failed (including unsupported platforms) |
494
+ | `binary_checksum_mismatch` | The downloaded binary's checksum does not match (possible tampering or corruption) |
495
+ | `gradle_lockfile_missing` | A Gradle project without `gradle.lockfile` (`scan_java_project`; the message explains how to generate it) |
496
+ | `path_outside_allowed_root` | The path is outside `OSV_MCP_ALLOWED_ROOT` (including when every manifest is excluded because its parent POM references a file outside the allowed root) |
497
+ | `no_packages_found` | No packages to scan (for example a `pom.xml` without dependencies) |
498
+ | `scan_failed` | OSV-Scanner exited abnormally (an excerpt of stderr is in `detail`) |
499
+ | `scan_timeout` | Timeout (120 seconds by default) |
500
+ | `too_many_concurrent_scans` | The concurrent scan limit (2 by default) was reached. Try again after the running scans finish |
501
+ | `output_too_large` | The output exceeds the size limit (32 MB by default) |
502
+ | `invalid_output` | The output could not be parsed as JSON |
503
+ | `invalid_vulnerability_id` | The vulnerability ID is malformed |
504
+ | `vulnerability_not_found` | No vulnerability with the ID exists in the OSV database |
505
+ | `api_request_failed` | The request to the OSV API failed (network, timeout, or a non-2xx response) |
506
+ | `internal_error` | An unexpected error (no internal details are returned) |
507
+
508
+ ## Security design
509
+
510
+ The following measures keep the vulnerability scanner itself from becoming an attack vector.
511
+
512
+ - **Supply chain**: The automatic download is limited to the official GitHub Releases and a pinned version, and is verified against **a SHA256 checksum embedded in the package** (the SHA256SUMS file from the release is not trusted, so tampering on the release side is detected). The binary is not made executable until it passes verification, and cached binaries are verified again on every use. `OSV_MCP_PREFER_DOWNLOAD=1` avoids unverified binaries on `PATH`
513
+ - **Command injection**: Commands are run with `spawn` and an argument array, never through a shell. OSV-Scanner receives only a fixed list of arguments, plus verified absolute paths
514
+ - **Snapshots (no gap between checking and reading)**: OSV-Scanner never receives the original files. Lockfiles, `pom.xml` (including the parent POM chain), and JAR/WARs are read safely once, copied into a private temporary directory (accessible only by the owner, deleted afterwards), and the copies are both checked and scanned. Replacing the original files or directories after the check has no effect on the results. Parent POMs are copied into the temporary directory at their original relative positions, so OSV-Scanner can follow relative paths but only finds the verified copies (references that climb out of the temporary directory with repeated `..` are excluded). Reads refuse a symbolic link at the final path component and anything that is not a regular file (so named pipes cannot stall the server), and afterwards the path is resolved again to confirm that it is still inside the boundary and is the same file that was opened. The copies are limited to 2 GiB in total (`scan_input_too_large`). When the server is terminated (SIGTERM/SIGINT/SIGHUP, or stdin closing), the temporary directories are deleted and running OSV-Scanner processes are stopped. Directories left behind by an uncatchable termination such as SIGKILL are deleted at a later startup (only directories whose names exactly match this server's prefixes, owned by the current user, not symbolic links, and unmodified for 24 hours or more)
515
+ - **Path traversal**: Input paths are resolved with `realpath` (following symbolic links) before the boundary check. Manifest searches do not follow symbolic links. OSV-Scanner never receives a directory, only the detected manifests, each with its format given explicitly (given a directory, OSV-Scanner also reads `requirements.txt` files there and follows their `-r ../x.txt` includes outside the scan scope). `requirements.txt` files are not passed as they are: only the dependency lines the server could interpret are normalized and written to a private copy without any include directives, so even if OSV-Scanner's interpretation of includes differs from the server's, files outside the scope are never read. A `pom.xml` whose parent POM chain references a file outside `OSV_MCP_ALLOWED_ROOT` is excluded ([Parent POMs](#parent-poms))
516
+ - **Denial of service**: Timeouts and limits on stdout and on the stderr excerpt. Scanner output is parsed defensively and malformed output does not throw. The number of concurrent scans is limited (2 by default) so that parallel requests cannot start unlimited processes. The server's own analysis reads each file once and reuses the result (lockfiles for npm workspace membership, shared `requirements.txt` includes, parent POMs), with a limit on the total amount read. Responses do not include the internal affected-range data, which keeps large scans to a fraction of their former size
517
+ - **Fail-closed mode**: `OSV_MCP_REQUIRE_ALLOWED_ROOT=1` refuses to start the server when no allowed root is set
518
+ - **Restricted permissions (optional)**: The server works under Node's permission model, reports denied access as `permission_denied`, and warns about missing permissions at startup ([Running with restricted permissions](#running-with-restricted-permissions))
519
+ - **Fixed and documented network destinations**: Dependency resolution is set to `deps.dev` explicitly, and the mode that connects to arbitrary repositories listed in the scanned `pom.xml` (`--data-source native`) is never used (guaranteed by tests). See [Network destinations and privacy](#network-destinations-and-privacy) for the destinations and for `OSV_MCP_NO_REMOTE_RESOLUTION=1`, which stops sending data to deps.dev
520
+ - **Information leakage**: Unexpected exceptions are reduced to `internal_error` without stack traces. Text from external sources (vulnerability summaries and so on) is returned as length-limited, structured data
521
+ - **Prompt injection**: Text from the OSV database (summary / details / IDs and so on) and OSV-Scanner's stderr are sanitized before being returned to the LLM client. Control characters (including ANSI escapes), zero-width characters, bidirectional control characters (such as RLO), Unicode tag characters (invisible text smuggling), and line separators (U+2028/2029) are removed, and NFC normalization is applied. All reads of external data go through a single sanitizing boundary, so nothing is missed
522
+
523
+ ## Development
507
524
 
508
525
  ```bash
509
- npm test # テスト実行(vitest)
510
- npx vitest run --coverage # カバレッジ計測
511
- npm run typecheck # 型チェック
512
- npm run build # dist/ へビルド
526
+ npm test # run the tests (vitest)
527
+ npx vitest run --coverage # measure coverage
528
+ npm run typecheck # type check
529
+ npm run build # build into dist/
513
530
  ```
514
531
 
515
- 設計メモ・残課題は [docs/DESIGN_TODO.md](docs/DESIGN_TODO.md) を参照してください。
516
-
517
- ## ロードマップ
518
-
519
- - [x] `suggest_fix` ツール: 現在のバージョンに最も近い系統の修正版を提案(3段階Tierフォールバック)
520
- - [x] `explain_vulnerability` ツール: 脆弱性の詳細説明(OSV API経由)
521
- - [x] npmパッケージ化(`npx osv-scanner-mcp`)
522
- - [x] OSV-Scannerバイナリの自動ダウンロード(チェックサム検証付き)
523
- - [x] Gradle対応(lockfile方式)
524
- - [x] `scan_java_artifact` ツール: JAR/WAR実体スキャン(lockfileが無い・shaded/fat JARのみのプロジェクト向け)
525
- - [x] `scan_project` ツール: Java / JavaScript / Python / Go のlockfileをまとめてスキャン
526
- - [x] `suggest_fix` のJavaScript / Go対応(semver)
527
- - [x] `suggest_fix` のPython対応(PEP 440)
528
- - [x] 直接/推移的依存の区別(npm・Go・requirements.txt)
529
-
530
- ## ライセンス
532
+ Design notes and open items are in [docs/DESIGN_TODO.md](docs/DESIGN_TODO.md) (in Japanese). Release notes are in [docs/releases](docs/releases).
533
+
534
+ ## Roadmap
535
+
536
+ - [x] `suggest_fix`: recommends the fix closest to the current release line (three-tier fallback)
537
+ - [x] `explain_vulnerability`: vulnerability details (through the OSV API)
538
+ - [x] npm package (`npx osv-scanner-mcp`)
539
+ - [x] Automatic OSV-Scanner download (with checksum verification)
540
+ - [x] Gradle support (lockfile approach)
541
+ - [x] `scan_java_artifact`: JAR/WAR scanning (for projects without a lockfile, or with only shaded/fat JARs)
542
+ - [x] `scan_project`: scans Java / JavaScript / Python / Go lockfiles together
543
+ - [x] `suggest_fix` for JavaScript / Go (SemVer)
544
+ - [x] `suggest_fix` for Python (PEP 440)
545
+ - [x] Direct and transitive dependencies (npm, Go, `requirements.txt`, `pom.xml`)
546
+ - [x] Checking recommended versions against the OSV database
547
+ - [x] Flagging inferred coordinates in JAR/WAR scans
548
+ - [x] Running under Node's permission model
549
+ - [x] English tool descriptions and messages
550
+ - [ ] Direct and transitive dependencies for `gradle.lockfile` and the YAML/TOML lockfiles
551
+
552
+ ## License
531
553
 
532
554
  [Apache License 2.0](LICENSE)