chainsaw scan
Scan packages for vulnerabilities and supply-chain conditions
Scan packages for vulnerabilities and supply-chain conditions
chainsaw scan [package@version | -] [flags]
Scan one or more packages using the Chainsaw server.
The server merges vulnerability data (CVE / CVSS / EPSS) with the supply-chain signals it holds for each coordinate: malware and typosquat status, install-script kind, publisher set and publisher changes, version anomalies, hidden Unicode, publish velocity, repo-link status, checksum and provenance. Which of those are populated depends on the ecosystem and on what the server could reach — see Coverage below.
Output formats (–format / –json / –output): table human-readable table (default) json structured envelope (–json is sugar for –format=json) sarif SARIF 2.1.0 log for code-scanning ingesters (normally with –output)
Batch input: chainsaw scan - read newline-delimited package specs / lockfile chainsaw scan –stdin paths from stdin (opt-in; bare scan never reads stdin)
Coverage: A package the server could not evaluate is reported as “not scanned”, never as clean, and the reason is printed to stderr. That state does NOT fail the build by default; pass –fail-on-unscanned (or set CHAINSAW_SCAN_FAIL_ON_UNSCANNED=1) to make it exit 1.
Exit codes: 0 clean — nothing at or above the gate 1 blocked — findings at or above the threshold (–fail-on, else any vulnerable package or high/critical supply-chain condition). Also returned when –fail-on-unscanned is set and a package could not be evaluated. 2 operational failure (network, server, IO) 3 configuration or authentication problem 4 bad invocation (unknown flag, unparseable package ref, –path with nothing scannable under it) 30 one or more manifests failed to parse (dependencies dropped) — the packages that did parse were still scanned. Same code, same meaning as chainsaw pr-scan. A block (1) outranks it.
Naming the registry: A lockfile scan (–path) knows which registry every coordinate came from. A ref typed on the command line usually does not: “commander@2.20.3” exists on npm AND on PyPI, and they are different packages. The scoped form (@scope/pkg) and a Go module path are unambiguous and resolved for you; anything else needs –ecosystem, and the scan says so rather than reporting a coordinate nobody could look up as clean.
Examples: chainsaw scan lodash@4.17.11 –ecosystem npm chainsaw scan @babel/core@7.24.0 chainsaw scan –path . chainsaw scan –path . –severity high chainsaw scan –path . –fail-on critical –json chainsaw scan –path . –fail-on-unscanned chainsaw scan –path . –format sarif –output results.sarif cat specs.txt | chainsaw scan -
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--ecosystem | string | — | Registry a bare package@version ref belongs to (npm|pip|maven|cargo|rubygems|composer|nuget|go|cocoapods|swift|pub|docker); inferred from the lockfile with –path |
--fail-on-unscanned | bool | — | Exit 1 when any package could not be evaluated (default: warn only; will become the default in a future major release) |
--fail-on | string | — | Exit 1 only when vulnerabilities at or above this severity are found |
--path | string | — | Scan all dependencies found in a local project manifest |
--severity | string | — | Minimum severity to display: critical, high, medium, low |
--stdin | bool | — | Read newline-delimited package specs / lockfile paths from stdin (opt-in; same as the ‘-’ arg) |
--timeout | duration | 10m0s | Maximum time to wait for the server to evaluate the submitted packages |
The global flags apply here too.