Vulnerability gating
Block by CVE, CVSS score, EPSS exploit probability, or CISA KEV membership. Combine freely; every operator is composable inside a single rule.
Policy
Chainsaw policy is declarative. You compose vulnerability, license, version, provenance, and client-context rules, then layer in the supply-chain attack signals CVE-based scanners miss. Every rule supports monitor, block, and quarantine modes, and every decision leaves a structured audit record.
Core rule families
Block by CVE, CVSS score, EPSS exploit probability, or CISA KEV membership. Combine freely; every operator is composable inside a single rule.
Allow, warn, or block by SPDX identifier. Separate policy for direct and transitive dependencies. SPDX-flavoured expressions for the edge cases.
Pin minimum versions, block deprecated or EOL releases, enforce semver ranges, require a minimum release age. Quarantines new versions while the ecosystem has time to react.
Require npm provenance, Sigstore signatures, Go's sum.golang.org, PGP for Maven and RubyGems, or InRelease/repomd hash-chain for APT/Yum/DNF. Trust roots are configurable.
Different policy for prod vs dev, per repository, per CI job, per geographic region. Tight where it matters, permissive where it doesn't.
Every exception carries a reviewer, a reason, and an expiry date — no permanent waivers by default. Exceptions are VEX-aware: chainsaw exception create accepts --cve, --decision (not_affected / affected / fixed / under_investigation), and --vex-note, so the audit log answers vendor questionnaires directly.
Supply-chain attack signals
Each signal evaluates at install time against the artifact, the registry metadata, and the publisher history. Combine them with vulnerability, license, version, and provenance rules in the same policy. Start in monitor mode, tune exceptions, flip to enforce one rule at a time.
Flags packages whose lifecycle hooks — preinstall/postinstall in npm, setup.py extensions in pip, build.rs in Cargo, Composer hooks — run remote fetches or decode base64 payloads. Refuses the install before the hook fires.
hasInstallScript · installScriptFetchesRemote Compares the current maintainer set against the package's history. A surprise publisher on a popular dependency blocks pending review. Works on npm, PyPI, RubyGems, NuGet, and Maven.
publisherChanged Catches semver regressions, multi-major skips, and backdated publish timestamps used to sneak a compromised version under a higher constraint. Narrow by kind: semver_regression, major_skip, timestamp_regression.
versionAnomaly · versionAnomalyKinds A rolling 24-hour counter per publisher. When one compromised account starts pushing dozens of tainted versions in a day, the burst trips the rule before your build runs. Threshold is tunable.
publishVelocityAnomaly Dependency confusion works because attackers publish your internal package names on public registries first. Reserved-namespace packs block the attack class up front. One-click apply of curated starters per ecosystem.
reservedNamespaces Blocks the install when the requested name is a near-miss of a popular package. BK-tree, homoglyph, and word-reorder matchers run against curated seed lists. Fourteen ecosystems including Go, CocoaPods, and GitHub Actions.
isSuspectedTyposquat A Docker-native malware index matched by digest and by name-plus-tag. Closes the container-image gap that public SCA feeds miss. Lookup is constant-time; a hit drops the trust score to -100.
isKnownMalicious (docker) Walks every image layer with Trivy under the hood. Vulnerabilities hidden beneath a clean top-level manifest are blocked at install; a clean tag no longer guarantees a clean image.
Container image analysis InRelease verification for APT, repomd.xml.asc for Yum/DNF. A mirror that tampers with a package between publish and fetch fails the chain. Debian and Fedora keyrings ship embedded.
hasProvenance (apt/yum/dnf) Native CVE detectors for Alpine, Debian, Red Hat, and Oracle Linux — distinct from upstream OSV, with each distro stream on its own update cadence. A vendor advisory becomes a block-list entry the same hour the distro publishes it.
distroCVE (alpine/debian/rhel/oracle) Bundled HF-native coordinate-match feed shipped in-process. Closes the gap where public SCA indexes lag on model-repo malware. Lookup is constant-time at resolve.
isKnownMalicious (huggingface) Unmaintained repos with an active npm publisher are a compromise waiting to happen. Each package gets a composite trust score folding in repo activity, ownership match, license, age, version count, and checksum presence. Set the floor you're comfortable with.
trustScoreMin Every upstream fetch is audited against the declared hash. Pick log, quarantine, or block mode per ecosystem. Distinguishes a real mismatch from an upstream that never published a hash.
checksum mode Coverage matrix
One row per attack class. The detection mechanism column names the module that runs the check; the data source column names the feed or signal it pulls from. Honest gaps — if a column is empty for an ecosystem, it's empty in the product.
| Attack class | Detection mechanism | Data source |
|---|---|---|
| Known vulnerability (CVE) | Vulnerability gate — CVSS, EPSS, CISA KEV, CVE ID match per ecosystem. | Trivy DB, OSV, GHSA, NVD, CISA KEV |
| Typosquatting | BK-tree + homoglyph + word-reorder matcher against curated seed lists across 14 ecosystems. | Curated popular-package seeds per ecosystem |
| Dependency confusion | Reserved-namespace packs block public publishes of your internal names. Birsan pattern refused up front. | Customer-declared internal namespaces + public-registry name-resolution check |
| Malware | Digest + name+tag match against malicious-package and malware indexes; ClamAV scanning on container layers. | OpenSSF malicious-packages, OpenSSF malware feed, ClamAV signatures |
| Hidden Unicode / Trojan Source | Refuses packages with zero-width, bidi-override, or Unicode-tag characters. Bounded at 500 files / 50 MiB per artifact. | Static source scan (no external feed required) |
| Install-script exfiltration | Flags lifecycle hooks that run remote fetches or decode base64 payloads — npm pre/postinstall, pip setup.py, Cargo build.rs, Composer hooks. | Static + symbolic analysis of declared lifecycle scripts |
| Maintainer-account takeover | Compares the current maintainer set against the package's publish history. Surprise publishers block pending review. | Per-registry publisher history (npm, PyPI, RubyGems, NuGet, Maven) |
| Publish-velocity worm bursts | Rolling 24-hour counter per publisher trips when one account starts pushing dozens of tainted versions. | Per-publisher publish-rate telemetry from registry events |
Internal & private packages
Chainsaw treats internal packages as first-class. You don't have to choose between running a private registry and running policy on what flows through it.
Declare the namespaces your org owns — @acme/* on npm,
com.acme.* on Maven, acme. on PyPI — and Chainsaw
refuses any public-registry publish that tries to squat them. Closes the
Birsan dependency-confusion class up front, no per-package allow-listing.
Point Chainsaw at your internal registry (JFrog Artifactory, Sonatype Nexus, Cloudsmith, GitHub Packages, AWS CodeArtifact) the same way you point it at npm or PyPI. The proxy authenticates outbound, applies the same policy, and caches results. Configurable per ecosystem; turn it off for any registry you don't want scanned.
Internal-package vulns surface on the same install-path audit row as public-package vulns — by repo, by CI job, by rule. If your internal package ships a vulnerable transitive (which is where most internal CVEs hide), the transitive-risk module walks the closure and the result lands in the inventory under the internal name.
Vendored & bundled dependencies
Some teams check vendored copies into the repo — vendor/ in Go,
third_party/ in monorepos, bundled wheels in Python projects, fat
JARs on the JVM. Chainsaw's SBOM walks those directories during inventory
generation, attributes findings back to the original upstream package, and
records the vendored copy alongside the install-path record so a single CVE
query catches both. Scan depth is configurable per repo — set the max walk
depth, exclude a directory, or skip vendored scanning entirely if your
compliance posture doesn't need it.
Ready to roll out?
Start free, switch to blocking when you're ready, or chat with us about custom deployments.