How to Block Malicious and Typosquatted Packages at Install Time with the Chainsaw CLI

Beginner 10 minutes Developers / Platform Engineers Getting Started

Run npm, pip, or go through the free Chainsaw CLI so malicious and typosquatted packages are refused before they enter your build — entirely on your machine, no server, nothing leaves the box.

Overview

The Chainsaw CLI can wrap your package manager and act as an install-path firewall: run chainsaw npm install … (or pip, or go) and Chainsaw evaluates each package before it enters your build, refuses anything malicious or typosquatted, then hands off to the real tool. The evaluation runs entirely on your machine — no server, no infrastructure — so you can adopt it on a laptop or a CI job. (Anonymous usage telemetry is off until you opt in; see Telemetry and privacy.)

This is the free, open-source CLI (github.com/chain305/chainsaw-core). No account required — not to block packages, and not for the feed either: chainsaw guard update (Step 7) pulls the full public OpenSSF malicious-packages feed directly from OpenSSF without sign-in. Guard blocks are recorded on this machine, and chainsaw guard status is always the local record. Signing in changes nothing about the feed — with telemetry on, blocks from this machine are also recorded against your org and appear on the dashboard alongside proxy and CI activity. With telemetry off, they stay here.

Prerequisites

  • The chainsaw CLI on your PATH (see Step 1).
  • npm, pip, or the Go toolchain installed (Chainsaw delegates to whichever you use).

Step 1: Install the CLI

Pre-built binary (detects your OS/arch, verifies the SHA-256 checksum):

curl -fsSL https://chain305.com/install.sh | sh

Or from source with the Go toolchain:

go install github.com/chain305/chainsaw-core/cmd/chainsaw@latest

Verify it’s wired up:

chainsaw doctor

Step 2: Guard an install

Put chainsaw in front of your normal command. A clean package installs as usual; a typosquat is refused before anything is fetched into your project.

# Clean — Chainsaw checks it, then runs the real `npm install lodash`.
chainsaw npm install lodash

# Typosquat — refused; the real npm is never invoked.
chainsaw npm install lodahs
chainsaw: BLOCKED npm:lodahs — looks like a typosquat of "lodash" (distance 1, edit-distance)
chainsaw: refused at install path. Nothing was installed.

The wrapper exits non-zero on a block, so it also gates CI steps.

Step 3: Known-malicious packages

Chainsaw ships an offline floor of well-known supply-chain attacks. These are refused with no network access:

chainsaw npm install event-stream@3.3.6   # the 2018 flatmap-stream attack
chainsaw pip install colourama            # typosquat-malware of colorama
chainsaw: BLOCKED npm:event-stream@3.3.6 — known-malicious (CHW-FLOOR-event-stream-3.3.6)

Clean versions of the same package are unaffected — the floor is version-exact, so npm install event-stream (a current release) installs normally.

Step 4: Scan a whole lockfile

With no named package, Chainsaw scans the resolved dependency tree, so a malicious transitive dependency is caught too:

chainsaw npm ci                              # scans package-lock.json
chainsaw pip install -r requirements.txt     # scans the requirements file
chainsaw: scanning 412 packages from lockfile
chainsaw: BLOCKED npm:ua-parser-js@0.7.29 — known-malicious (CHW-FLOOR-ua-parser-js)
chainsaw: refused at install path. Nothing was installed.

Step 5: Go modules

chainsaw go get github.com/some/module@v1.2.3

Typing chainsaw each time is easy to forget. Add a one-liner to your shell config and npm, pip, and go route through the guard transparently:

# ~/.zshrc or ~/.bashrc
eval "$(chainsaw guard init zsh)"

# ~/.config/fish/config.fish
chainsaw guard init fish | source

Now npm install … is checked automatically — the guard evaluates the package, then hands off to the real npm. (It’s recursion-safe: Chainsaw resolves the real tool via PATH, which shell functions don’t shadow.)

Step 7: Add full known-malicious coverage (optional)

The built-in floor covers the famous attacks offline. To pull the full OpenSSF malicious-packages dataset for local use, run the opt-in updater (the only command that fetches feed data, and only when you run it):

chainsaw guard update

It writes a local cache that the guard merges on top of its floor; after that, known-malicious coverage is the full set, still evaluated on your machine. chainsaw guard update pulls that data directly from OpenSSF — no Chainsaw sign-in required — and the built-in floor keeps working offline either way.

Check what coverage and feed you have at any time:

chainsaw guard status

Enable shell completion (optional)

chainsaw ships tab-completion for bash, zsh, fish, and PowerShell. Load it for the current shell:

# zsh (most macOS setups) — add to ~/.zshrc:
source <(chainsaw completion zsh)

# bash — add to ~/.bashrc:
source <(chainsaw completion bash)

# fish:
chainsaw completion fish | source

Completion covers subcommands, their flags, and the guarded package managers (chainsaw npm, chainsaw pip, …). Run chainsaw completion --help for the per-shell path that persists across sessions.

Telemetry and privacy

Anonymous usage telemetry is off until you opt in. The first interactive run asks yes/no (default No); answer yes and the guard reports how it’s adopted and where it refuses packages. If it can’t ask — non-interactive shells, CI — it stays off and collects nothing until you run chainsaw telemetry on. Your protection is always evaluated entirely on your machine — telemetry is a separate, after-the-fact event. Once you’ve opted in and no server is configured, events go to the public ingest at https://chain305.com.

Turn it on or off any time:

chainsaw telemetry on      # opt in (persisted)
chainsaw telemetry off     # opt back out (persisted)

Force it off regardless of consent:

export CHAINSAW_TELEMETRY_DISABLED=1   # disable all telemetry
export CHAINSAW_OFFLINE=1              # disable telemetry + make no network calls at all
export CHAINSAW_NO_NUDGE=1             # silence in-product CTAs (telemetry consent unaffected)

Full collection details — the exact events and fields — are in the Telemetry reference.

How it decides (and what it covers)

SignalCoverageNetwork
Typosquatnpm, PyPI, Gooffline
Known-malicious floorcurated famous attacks (npm + PyPI)offline
Known-malicious (full)full OpenSSF set after chainsaw guard updateopt-in fetch, then offline

Block policy: known-malicious and high-confidence typosquats are refused; medium-confidence typosquats are allowed with a warning. If signal coverage is thin, the guard fails open with a visible notice rather than blocking your work — a tool that breaks npm install gets uninstalled.

Next Steps