npmguard
Allows AI agents to assess the risk of npm packages before installation, checking for typosquats, known vulnerabilities, lifecycle scripts, and other signals.
npmguard
A native pre-install risk gate for npm packages, with an MCP tool for AI coding agents. Pre-install risk scoring + MCP server, distributed outside the npm ecosystem so it can't be compromised by the thing it's protecting you from.
v0.1 is a risk checker + MCP verdict gate. It is not yet a real npm wrapper, installer, or sandbox. npmguard check and npmguard install both produce a verdict; the actual npm install subprocess execution and cross-platform sandbox land in v0.2. See the roadmap below.

npmguard install lodahs — a real typosquat of lodash, refused before lifecycle scripts can run:

Also available as GIF or MP4. Live verdict against the npm registry — lodahs is in OSV's malware namespace (MAL-2025-25502). Theme: atlas-ragnarok. Regenerate with sh docs/_theme/gen.sh (needs vhs, ffmpeg, webp, pillow, numpy).
Why
Across 2025–2026 the npm ecosystem absorbed a series of worm-style supply chain attacks that ran inside preinstall / install / postinstall scripts the moment a downstream user ran npm install — Shai-Hulud (Sep 2025), SHA1-Hulud (Nov 2025), the Axios compromise (Mar 2026), Mini Shai-Hulud (May 2026). Defender wins or loses before the install completes, not after.
Existing defenses leave a specific gap:
npq,safe-npm/socket npm,npm-riskship as npm packages. They run on the thing they're protecting you from. If the wrapper is ever compromised, you've made the problem worse.pnpm v10+, Bun disable lifecycle scripts by default — but only for users who've moved offnpm. The npm majority is unprotected.npm audit, Snyk, Dependabot,lavamoat/allow-scriptsare excellent at CVE scanning and allow-list management, but they're not a pre-install heuristic gate, and none of them gate AI coding assistants like Claude Code, Cursor, or Windsurf when they runnpm installon your behalf.
npmguard fills the specific gap of pre-install risk scoring + AI-agent gate via MCP, shipped as a single binary outside npm. Zero external dependencies at runtime beyond the registries it queries.
Install
Pick whichever fits your machine:
# macOS (Apple Silicon)
curl -L -o npmguard.tar.gz \
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.2-aarch64-apple-darwin.tar.gz
tar -xzf npmguard.tar.gz
sudo mv npmguard-v0.1.2-aarch64-apple-darwin/npmguard* /usr/local/bin/
# macOS (Intel)
# https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.2-x86_64-apple-darwin.tar.gz
# Linux (x86_64)
# https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.2-x86_64-unknown-linux-gnu.tar.gz
# Linux (aarch64)
# https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.2-aarch64-unknown-linux-gnu.tar.gz
# Windows (x86_64)
# https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.2-x86_64-pc-windows-msvc.zip
# Build from source (any OS with Rust ≥ 1.75)
cargo install --git https://github.com/AyoubTadlaoui/npmguard --bin npmguard
cargo install --git https://github.com/AyoubTadlaoui/npmguard --bin npmguard-mcp
# Prebuilt binaries
# https://github.com/AyoubTadlaoui/npmguard/releasesEvery release ships a SHA256SUMS.txt — verify before extracting:
shasum -a 256 -c <(grep npmguard-v0.1.2-aarch64-apple-darwin.tar.gz SHA256SUMS.txt)Docker (npmguard-mcp only)
docker pull ghcr.io/ayoubtadlaoui/npmguard-mcp:latest
docker run --rm -i ghcr.io/ayoubtadlaoui/npmguard-mcp:latestThe Docker image is provided for MCP catalogs and CI; native binaries remain the recommended local install path. The image ships only the npmguard-mcp server (not the CLI), runs as a non-root user, and has no exposed ports — MCP hosts communicate over stdio.
Homebrew tap, Scoop bucket, curl ... | sh installer, and AUR land with v0.2 alongside the sandbox layer. See DISTRIBUTION.md (planned) for the full channel matrix.
Quickstart — CLI
# Evaluate the latest version, no install.
npmguard check axios
# Pinned version, JSON output (machine-readable for CI).
npmguard check --json @ctrl/tinycolor@4.1.1
# Install path: v0.1 prints the verdict and stops; v0.2 will run `npm install`
# inside the sandbox layer if the verdict allows it.
npmguard install lodash@4.17.21
# Auto-accept warn-level (still refuses block-level).
npmguard install --yes some-fresh-packageSample output, real live verdict against the registry:
npmguard lodahs@0.0.1-security → score 115 / 200 (block, thresholds warn=30 block=70)
10 pts SoleMaintainer single maintainer: adam_baldwin
25 pts Typosquat name 'lodahs' is 1 edit away from popular package 'lodash'
80 pts KnownCve 1 CONFIRMED MALICIOUS by OSV for this version: MAL-2025-25502
blocked: refusing to install lodahs (score 115 ≥ block threshold 70)All flags:
Flag | Default | Meaning |
|
| Emit verdict as JSON instead of colored text |
|
| Disable ANSI color escapes |
|
| Skip the local SQLite verdict cache |
|
| Increase log verbosity |
|
| Auto-accept warn-level verdicts; block-level still refuses |
Quickstart — MCP
The npmguard-mcp binary speaks the Model Context Protocol over stdio. Add it to your MCP host's config (for Claude Code, that's ~/.claude.json):
{
"mcpServers": {
"npmguard": {
"command": "/usr/local/bin/npmguard-mcp"
}
}
}It exposes one tool, install_package(name, version?), returning a structured verdict the model can act on:
{
"package": "lodahs",
"resolved_version": "0.0.1-security",
"level": "block",
"score": 115,
"signals": [
{ "kind": "SoleMaintainer", "points": 10, "detail": "single maintainer: adam_baldwin" },
{ "kind": "Typosquat", "points": 25, "detail": "name 'lodahs' is 1 edit away from popular package 'lodash'" },
{ "kind": "KnownCve", "points": 80, "detail": "1 CONFIRMED MALICIOUS by OSV for this version: MAL-2025-25502" }
],
"recommendation": "Block — do NOT install this package without explicit user override. Present the signals and ask the user to confirm."
}The model gets the recommendation in its own message, so even if the user said "just install whatever you need", the assistant has the structured signal to stop and ask.
Risk signals
Signal | Points | Triggered when |
| 30 | Package defines |
| 25 / 10 | Version published < 7 / 30 days ago |
| 20 | Version published after a > 180-day publish gap (dormant package resurrection) |
| 10 | Package has exactly one maintainer |
| 15 / 10 | Linked GitHub repo is archived / has zero stars and no commits in 6 months |
| 25 | Name is one Damerau-Levenshtein edit from a popular package (catches char swaps like |
| 80 / 50 / 20 / 10 / 5 | OSV.dev advisory present. 80 if it's a |
| 10 | npm registry marks this version deprecated |
Composite score is the sum (capped at 200). Default thresholds: warn ≥ 30, block ≥ 70. Tunable per project via config (planned for v0.2).
Weights are starting values, not science. They will be tuned against corpus/ and the values published as part of each release. PRs welcome.
What npmguard does NOT do
Honesty is the contract.
npmguard cannot prove packages are safe. It can stop known-malicious packages (OSV
MAL-*), flag typosquats, surface lifecycle scripts / package age / maintainer churn, and route AI coding agents through the same verdict. That's it. Everything below is what the v1.0 sentence will eventually add — see ROADMAP.md.
What's still missing in v0.1:
Doesn't catch attacks that pass all heuristic checks. A clean-history maintainer-account-takeover that ships a release matching every "looks normal" signal will still install. The v0.2 release-anomaly engine (per-version
package.jsondiff) is the planned answer.Doesn't yet verify npm provenance / package signatures. A historical provenance attestation suddenly missing is a strong takeover signal — that lands in v0.3.
Doesn't yet sandbox lifecycle scripts or wrap the real
npm installsubprocess. v0.1 surfaces the verdict and stops; v0.2 ships the sandbox (landlock / sandbox-exec / Job Object) +--ignore-scriptsenforcement + per-script allow-list.Doesn't protect against malicious code that runs at import time, not install time. If a package is benign at install but evil when imported, this tool isn't in the path. That's a runtime-sandbox problem and is deliberately out of scope — see ROADMAP.md.
Doesn't replace
npm audit, Snyk, Socket, Dependabot, or code review. It's an additional layer. v0.3 adds--with npm-audit/--with osv-lockfile/--with socketadapters so npmguard becomes the policy gate on top of them rather than a redundant scanner.Is not a guarantee. Any tool claiming "secure" is lying. This one says "reduces blast radius" and stops there.
Versioning & releases
npmguard follows Semantic Versioning. While the project is 0.x:
The CLI is treated as stable for end users — flag names and exit codes won't change without a major bump.
The MCP tool surface (
install_packageinput/output schema) may make minor additive changes between0.xreleases. Anything breaking is called out in CHANGELOG.md.
Tagged releases publish prebuilt binaries to the Releases page (macOS x86_64 + arm64, Linux x86_64 + arm64, Windows x86_64) via a cross-platform GitHub Actions matrix.
Roadmap (full reasoning + considered-and-rejected scope in ROADMAP.md):
Phase | Headline |
v0.1 (shipped) | Risk engine + CLI + MCP server + SQLite cache + GitHub Releases |
v0.2 | Real |
v0.3 | Provenance / signature verification + scanner adapters ( |
v0.4 |
|
v0.5 | Organization presets + MCP marketplace placement (Claude Code, Cursor, Smithery) |
v1.0 | Frozen Rust API, frozen MCP tool schema, frozen JSON output, integration into AI-assistant default docs |
Runtime sandboxing (npmguard run npm test) is deliberately out of scope — see ROADMAP.md § Considered and kept out of scope for the reasoning.
Contributing
PRs and issues welcome. The short version:
cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
NPMGUARD_CORPUS=1 cargo test --test corpus -- --nocapture # live network testOpen the PR once that's clean.
License
MIT — see LICENSE.
About the author
Ayoub Tadlaoui — Atlas Kaisar — a problem-solver from Morocco, building software since 2016.
"High performance knows no part-time commitment."
Maintenance
Tools
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AyoubTadlaoui/npmguard'
If you have feedback or need assistance with the MCP directory API, please join our Discord server