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

Beginner 10 minutes Developers / Platform Engineers Getting Started Updated

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.

Video: Install the CLI | Chainsaw tutorial 1.1
Video: Turn the install guard on | Chainsaw tutorial 1.2
Video: Scan a project you already have | Chainsaw tutorial 1.4
Video: Refresh the feed, including offline | Chainsaw tutorial 1.5
Video: Protect your machine too | Chainsaw tutorial 2.9

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 (one command)

macOS and Linux:

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

Windows (PowerShell):

iwr -useb https://chain305.com/install.ps1 | iex

That one command installs the CLI (it detects your OS and arch and verifies the SHA-256 checksum) and turns the install guard on: it adds one line to your shell config (your PowerShell profile on Windows), so in every new terminal npm, pip, go, cargo and gem installs are checked before they download. The installer ends with a Guard: line that says whether the guard is on.

  • To install the binary only, set CHAINSAW_NO_GUARD=1 on the shell that runs the script: curl -fsSL https://chain305.com/install.sh | CHAINSAW_NO_GUARD=1 sh.
  • In CI (CI set) the installer skips the guard automatically; see Unattended install in CI.
  • Windows: if your PowerShell execution policy is Restricted (the default on many PCs), profiles don’t load. The installer says so instead of claiming the guard is on. Allow it for your user with Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.

Or build from source with the Go toolchain. This installs the binary only, so turn the guard on yourself afterwards:

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

Open a new terminal, then check it’s wired up:

chainsaw doctor
chainsaw guard status

Step 2: Guard an install

With the guard on, use your normal command: npm install lodahs is refused on its own. You can also put chainsaw in front of a command explicitly, which works even where the guard isn’t loaded (a script, or cmd.exe). 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

Step 6: It’s already automatic

The installer turned the guard on in Step 1, so npm, pip, go, cargo and gem route through it in every new terminal. It added this one line to your shell config, which you can read and remove at any time:

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

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

If the Guard: line said it was skipped, or you installed with go install, add it yourself with chainsaw guard init --install (it’s idempotent; preview first with --dry-run). For the current shell only, run the eval line above.

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