# How it works | Chainsaw

> Chainsaw is a firewall for your package installs. Every npm install, pip install, docker pull runs through a policy engine before it touches the registry — allow it (cached), or block it with a clear error.

Source: https://chain305.com/product/how-it-works/

---

How it works

# Chainsaw is a firewall for your package installs.

Every `npm install`, `pip install` and `docker pull` meets a policy engine on its way to your machine.

1.  01 · Your package manager
    
    `npm install <pkg>`
    
    registry URL points at Chainsaw
    

3.  02 · Chainsaw proxy
    
    -   CVE, CVSS, EPSS, KEV
    -   license and version rules
    -   provenance
    -   supply-chain signals
    
    before any bytes reach the client
    

5.   Refused
    
    the error names the rule that fired
    
     Allowed
    
    streamed through the content-addressed cache
    

Unchanged: `npm install`, lockfiles, CI jobs, IDE tooling and registry auth.

Why this exists

## Supply-chain attacks don't look like CVEs.

`event-stream`, `xz-utils` and `tj-actions/changed-files` reached developer machines before any scanner had a CVE to match.

01

Setup · one-time

### Point one URL at Chainsaw

~/.npmrc

```
registry=https://registry.npmjs.org/
registry=https://CLIENT_ID:CLIENT_SECRET@chain305.com/chainproxy/repository/@default/npmjs/
```

One URL per ecosystem, no SDK or CI plugin. [Per-ecosystem guides →](https://docs.chain305.com/categories/getting-started/)

02

Every install · runtime

### Rules run in parallel, then allow or refuse

Rule evaluation takes low single-digit milliseconds.

Supply-chain signals, by ecosystem

Install-script exfiltration

npm / pip / rubygems / cargo / composer

Maintainer-account takeover

npm / pip / rubygems / nuget / maven / gradle

Publish-velocity bursts

npm / pip / rubygems / nuget

Hidden characters in package

source-archive ecosystems

Typosquat across 15 ecosystems

not APT / Yum / DNF

Version anomalies

every SemVer ecosystem

Reserved-namespace dependency confusion

universal

Container-image malware feed

Docker

Per-layer image enforcement

Docker

OS-package hash-chain provenance

APT / Yum / DNF

Repo liveness + ownership match

trust-score input

Checksum fail-closed enforcement

npm / pip / rubygems / composer / maven / gradle / nuget / cargo

03

Rollout · ongoing

### Monitor first, enforce when ready

policy.yaml

```
name: "Block critical vulnerabilities"
mode: "monitor"  # week 1–2: just record what would fire
mode: "block"    # week 3+: block the install
conditions:
  cvssMin: 9.0
  epssMin: 0.5
```

Flip per rule, per repo or per team. Every decision is logged.

Where every decision lands

## Every allow and refusal rolls up to Overview.

![Chainsaw Overview dashboard showing blocked, allowed, and flagged install counts as sparklines, supply-chain firewall posture, and a patch-priority queue.](/demo/overview.png?v=3)

Overview Block, allow and flag counts, posture and the patch-priority queue. Demo org, 30 days of synthetic install traffic.

When things go wrong

## By default, your builds don't break.

What fails

What happens

Threat-intel feed or database degraded

Fails open and writes the gap to the audit trail. Set CHAINSAW\_COVERAGE\_MODE=closed and name your mandatory sources to refuse anything they could not check.

The proxy process is down

Run it HA. That is a deployment question, not a policy one.

Upstream registry is down

The cache serves previously allowed versions. New ones fail with the upstream's own error.

A rule is too aggressive

One-click exception with a reviewer, a reason and an expiry.

[Read the getting-started guides →](https://docs.chain305.com/categories/getting-started/)

Ready to roll out?

## Put Chainsaw on the install path

Start free in monitor mode. See what would be refused, then flip to enforce when you've seen the data.

[Get started](https://chain305.com/chainsaw/signup) [Talk to sales](https://cal.com/chain305/30min)

---

## Long form

The full text behind this page, including detail the page itself leaves out.

How it works

### Chainsaw is a firewall for your package installs.

Every `npm install`, `pip install`, `docker pull` runs through a policy engine before it touches the registry. Allow it (cached), or block it with a clear error. Watch one of each below.

Scenario one: npm install react. Chainsaw evaluates CVE, license, provenance, and every applicable supply-chain signal in parallel. All checks pass. The package is streamed from the npm upstream through Chainsaw's content-addressed cache back to the developer. The terminal prints: added 1 package in 482ms. Scenario two: npm install log4j-core version 2.14.1. Chainsaw's CVE rule matches CVE-2021-44228 with a CVSS score of 10.0. The install is blocked before reaching the upstream registry. The terminal prints a structured error naming the rule block-critical-vulns and the exception contact security at your-org dot com.

-   `npm install`
-   lockfiles
-   CI jobs
-   IDE tooling
-   registry auth

**What changes for developers:** almost nothing. No SDK, no laptop agent, no CI plugin. The only difference is that bad packages fail with a message telling them why.

Why this exists

#### Supply-chain attacks don't look like CVEs.

`event-stream`, `ua-parser-js`, `xz-utils`, and the March 2025 `tj-actions/changed-files` GitHub Action compromise all shipped to developer machines before any vulnerability scanner had a CVE to match. A post-hoc SCA finds the bad package _after_ it's on disk — sometimes after the postinstall script has already run. Chainsaw refuses these at install time, on rules you can read and change.

From `npm install` to package-on-disk

#### Three phases: set it up once, run every install through it, roll it out without breaking builds.

01

Setup · one-time

##### Point one URL at Chainsaw

Change one registry URL in the config your package manager already reads. Nothing else changes — no SDK, no laptop agent, no CI plugin, no new build step.

~/.npmrc

```
// before
registry=https://registry.npmjs.org/
// after
registry=https://your-org.chain305.com/npm/
```

Same pattern for `pip.conf`, `settings.xml`, `Dockerfile` `FROM` lines, NuGet, Cargo, Go, Composer, APT — one URL per ecosystem. [See the per-ecosystem guides →](https://docs.chain305.com/categories/getting-started/)

02

Every install · runtime

##### Policy evaluates, then allow or block

On every request, Chainsaw evaluates the package in parallel against your rules — low single-digit milliseconds — before forwarding to the upstream registry or returning an error.

Allow path

-   Rules pass in parallel: vulnerability gates, licenses, versions, provenance (_who published it, signed by whom_), plus up to 12 supply-chain attack signals depending on the ecosystem.
-   Package streams back through the content-addressed cache (_deduped by hash — the second install of the same version is faster than upstream_).
-   Developer sees the usual `added 1 package`. Chainsaw is invisible.

Block path

The developer sees the exact rule that fired, in their own terminal:

```
$ npm install log4j-core@2.14.1
npm ERR! Chainsaw: blocked
npm ERR!   rule:    block-critical-vulns
npm ERR!   reason:  CVE-2021-44228 (CVSS 10.0, EPSS 0.97)
npm ERR!   contact: security@your-org.com
```

EPSS is the _likelihood of real-world exploitation_ — it filters out the long tail of "technically a CVE, nobody exploits it" noise.

What rules run on every request

###### Six rule families

-   **Vulnerability gates** — CVE, CVSS, EPSS, KEV
-   **Licenses** — SPDX allowlist/denylist per ecosystem
-   **Versions** — pinned, semver windows, release-age floors
-   **Provenance** — signed builds, trusted publishers
-   **Client context** — who's installing, from where, into what
-   **Exceptions** — reviewed, dated, scoped overrides

###### Up to 12 supply-chain attack signals

-   Install-script exfiltration (_npm / pip / rubygems / cargo / composer_)
-   Maintainer-account takeover (_npm / pip / rubygems / nuget / maven / gradle_)
-   Publish-velocity bursts (_npm / pip / rubygems / nuget_)
-   Hidden characters in package (_source-archive ecosystems_)
-   Typosquat across 15 ecosystems (_not APT / Yum / DNF_)
-   Version anomalies (_every SemVer ecosystem_)
-   Reserved-namespace dependency confusion (_universal_)
-   Container-image malware feed (_Docker_)
-   Per-layer image enforcement (_Docker_)
-   OS-package hash-chain provenance (_APT / Yum / DNF_)
-   Repo liveness + ownership match (_trust-score input_)
-   Checksum fail-closed enforcement (_npm / pip / rubygems / composer / maven / gradle / nuget / cargo_)

03

Rollout · ongoing

##### Monitor first, enforce when ready, prove it afterward

Every rule ships with a monitor mode: the decision is recorded, but the install still succeeds. You see exactly what _would have_ been blocked across every repo and pipeline, add exceptions where needed, then flip the rule to enforce — per rule, per repo, per team.

policy.yaml

```
name: "Block critical vulnerabilities"
mode: "monitor"   # week 1–2: just record what would fire
### week 3+: change to mode: "block" to refuse the install
conditions:
  cvssMin: 9.0
  epssMin: 0.5
```

Every allow/block is logged with timestamp, user, rule, and package metadata. Export a CycloneDX SBOM (_standard file that lists everything you shipped_) per repo, stream the audit log to your SIEM, or roll a policy back from the dashboard — no developer workstation touched.

Where every decision lands

#### Every allow and block rolls up to the Overview dashboard.

![Chainsaw Overview dashboard showing blocked, allowed, and flagged install counts as sparklines, supply-chain firewall posture, and a patch-priority queue.](/demo/overview.png?v=3)

Overview A capture of the Overview dashboard — block, allow, and flag counts, current posture, and the patch-priority queue. Demo org seeded with 30 days of synthetic install traffic.

When things go wrong

#### Three failure modes, three answers. By default, your builds don't break.

-   **Intel or DB degraded:** fails open with an audit row — or refuses, if you configure it to.
-   **Upstream down:** cache serves previously-allowed installs.
-   **Rule too aggressive:** one-click exception with reviewer, reason, expiry.

##### Chainsaw itself is degraded

Two different outages, two different answers. The proxy sits in your install path, so if the process itself is down, run it HA — that's a deployment question, not a policy one. If the proxy is up but its database or a threat-intel feed is degraded, installs proceed and the gap is recorded in the audit trail: Chainsaw fails open by default rather than breaking your builds. If you'd rather it stopped, set `CHAINSAW_COVERAGE_MODE=closed` and name the data sources you treat as mandatory — Chainsaw then blocks anything it couldn't fully check, and tells you which source was missing.

##### The upstream registry is down

npm, PyPI, or Docker Hub having a bad day doesn't block your builds. Cached versions serve from Chainsaw's content-addressed blob store. Only packages you haven't installed before fail, and they fail with the upstream's own error — not ours.

##### A rule is too aggressive

A blocked legitimate install is one click away from an exception. The exception carries a reviewer, a reason, and an expiry date. The reviewer dashboard queues the request; the developer sees a structured error naming the rule and the exception contact. No escalation to platform-eng needed.

**Still skeptical?** Start in monitor mode. Every rule supports it out of the box — we log the decision but still let installs through, so you can measure exactly what _would have_ been blocked across every repo and pipeline before you enforce a single thing.

[Read the getting-started guides →](https://docs.chain305.com/categories/getting-started/)

Ready to roll out?

#### Put Chainsaw on the install path

Start free in monitor mode. See what would be refused, then flip to enforce when you've seen the data.

[Get started](https://chain305.com/chainsaw/signup) [Talk to sales](https://cal.com/chain305/30min)
