Drop-in npm install replacement that sandboxes every postinstall script,
statically analyzes for threats, and shares alerts across a decentralized threat intelligence network.
A live terminal running safenpm's actual algorithms in your browser. Type any command or click a quick demo below.
Every postinstall script runs inside an OS-level sandbox with no network access. Malicious packages can't phone home, exfiltrate tokens, or download payloads.
19 detection rules scan scripts before execution. Catches curl/wget piping, DNS exfil, env stealing, base64 obfuscation, and SSH key access with severity-weighted scoring.
Levenshtein distance plus 5 attack pattern detectors (char-swap, substitution, scope confusion) check every dependency against 80+ popular npm packages.
Caches install scripts per project. On upgrade, compares against the cached version to surface new threats, new warnings, and risk score changes.
Queries the npm registry for publisher history. Alerts you when the person publishing a package changes between versions — a signal of account takeover.
Parses package-lock.json to catch git dependencies, custom registries, missing integrity hashes, weak algorithms, and stale lockfiles.
Scores every package 0-100 based on maintainer count, license, repository presence, dependency weight, and maturity. Aggregates into a project health grade.
When a package is blocked, the signal is anonymously reported to the safenpm network. Every install queries it back — if one developer gets hit, everyone is warned. No identifying data ever leaves your machine.
Full JSON output mode, non-zero exit codes on blocks, audit log with auto-rotation, and a standalone scan command for pipeline integration.
Single command gives your project a letter grade (A+ to F) with weighted scores across 6 categories. Every finding comes with an actionable fix suggestion.
Detected a typosquat? safenpm fix automatically removes the suspect and installs the legitimate package. Preview with --dry-run before applying.
Git-diff-style output showing exactly what changed in each dependency update — script modifications, added/removed deps, and new files. Snapshot and compare.
Signals contain only the package name, script content hash, and block reason. No IP addresses, usernames, project names, or file paths are transmitted.
Threat queries happen on every install with a local cache layer. New threats propagate across the network within minutes of the first detection.
Run with --no-report to disable outbound signal reporting. Threat intel queries still work — you benefit from the network without contributing.
| Platform | Backend | Network Block | FS Sandboxing | Requires |
|---|---|---|---|---|
| macOS | sandbox-exec |
Built-in | ||
| Linux | firejail |
apt install firejail |
||
| Windows (admin) | Firewall + ACLs | Run as Administrator | ||
| Windows (WSL) | firejail via WSL |
WSL + firejail |
Install safenpm globally and use it as a drop-in replacement for npm install.
npm install -g @abgunaydin/safenpm
# Instead of npm install:
safenpm install
# Install specific packages:
safenpm install axios lodash express
# Short form:
safenpm i
safenpm runs npm install --ignore-scripts first to install packages normally,
then discovers all postinstall/preinstall/install hooks and runs each one inside an OS-native sandbox.
If a script tries to access the network or read sensitive files, it gets blocked and reported.
safenpm i --dry-run
| Flag | Short | Description |
|---|---|---|
| --dry-run | -n | Preview what would be sandboxed without executing |
| --allow <pkg,...> | Skip sandboxing for trusted packages | |
| --scan | -S | Enable deep scan (typosquat, diffing, intel, lockfile, reputation) |
| --json | Machine-readable JSON output for CI pipelines | |
| --interactive | -I | Prompt on each blocked package: retry / skip / abort |
| --loose | Network-only sandbox (no filesystem restrictions) | |
| --no-report | Disable anonymous signal reporting |
| Command | Description |
|---|---|
| install / i | Install packages with sandboxing |
| doctor | Health report card with letter grade and fixes |
| fix | Auto-fix typosquats and remove malicious packages |
| diff | Show what changed in dependencies since snapshot |
| scan | Standalone deep scan (no install) |
| audit | View recent safenpm run history |
The --scan flag activates all six intelligence modules for a comprehensive
security audit of your dependency tree.
# During install:
safenpm install --scan
# Standalone (no install, analysis only):
safenpm scan
# JSON output for CI:
safenpm scan --json
Typosquat detection checks every package name against 80+ popular npm packages using Levenshtein distance and 5 attack pattern detectors including char-swap, substitution (0→o, rn→m), scope confusion, and edit distance analysis.
Behavioral diffing compares install scripts against a cached baseline from your last install. If a package upgrade introduces new curl calls, DNS lookups, or other suspicious patterns, you'll see the exact new warnings and risk delta.
Maintainer change detection queries the npm registry for the publisher of each version. If the account publishing the current version differs from who published the previous one, that's flagged as a potential account takeover.
Lockfile integrity audit parses package-lock.json and checks for git dependencies, custom registries, missing integrity hashes, weak hash algorithms, and stale lockfiles.
Reputation scoring evaluates every package based on maintainer count, license, repository presence, dependency weight, install scripts, and version maturity, producing a 0-100 score and a project-level health grade.
Community threat intel runs automatically on every install — not just with --scan.
Each time you run safenpm install, packages are checked against the live
decentralized intelligence network, surfacing flagged packages with report counts and attack categories
before any scripts execute.
Some packages (like bcrypt, sharp, or node-gyp native modules) legitimately need install scripts. Allowlist them to skip sandboxing.
safenpm i --allow bcrypt,sharp,@img/sharp-darwin-arm64
# .safenpmrc in project root
bcrypt
sharp
@img/*
@mycompany/*
# ~/.safenpmrc
bcrypt
node-gyp
Allowlisted packages still run, but outside the sandbox. The allowlist is loaded from three sources
(CLI flags, project .safenpmrc, home ~/.safenpmrc)
and merged. Scope wildcards (@scope/*) match all packages in that scope.
- name: Install with safenpm
run: |
npm install -g @abgunaydin/safenpm
safenpm install --json --scan --no-report | tee safenpm-report.json
- name: Check for blocks
run: |
BLOCKED=$(cat safenpm-report.json | jq '.summary.blocked')
TYPOS=$(cat safenpm-report.json | jq '.summary.typosquats')
if [ "$BLOCKED" -gt 0 ] || [ "$TYPOS" -gt 0 ]; then
echo "::error::safenpm found $BLOCKED blocked scripts and $TYPOS typosquat suspects"
exit 1
fi
{
"version": "1.0.0",
"backend": "sandbox-exec (macOS)",
"packages": [...],
"typosquats": [...],
"lockfileAudit": { "score": 85, "issues": [...] },
"reputationSummary": { "overallScore": 72, ... },
"summary": {
"total": 5, "blocked": 1, "clean": 3,
"allowed": 1, "warnings": 8,
"typosquats": 0, "maintainerChanges": 0,
"lockfileIssues": 2, "reputationScore": 72
}
}
# Fail the build if project health is D or F:
safenpm doctor --json
# (exits non-zero on score < 60)
# Just scan existing node_modules:
safenpm scan --json
Every run is logged to ~/.safenpm/audit.log in JSONL format with auto-rotation
at 5MB. Query it with safenpm audit or safenpm audit --json.
safenpm's analyzer runs 19 rules across 3 severity tiers before scripts are sandboxed. Each rule has a weight; the total is capped at 100.
curl/wget downloads, netcat, require('https'), fetch(), require('dns'), process.env access, ~/.ssh access, sensitive dotfile reads (.aws, .npmrc, .docker, .kube), eval(), base64 encoding/decoding, pipe-to-shell execution.
/etc/passwd reads, $HOME access, child_process spawning, hex/unicode obfuscation, net/dgram socket creation.
node-gyp native builds, prebuild-install, node-pre-gyp. These are common in legitimate packages.
Scores map to levels: critical (60+), suspicious (30-59), low (1-29), clean (0).
safenpm doctor runs every analysis module and produces a letter grade
from A+ to F, with weighted scores across 6 categories.
# Run a health check:
safenpm doctor
# JSON output for CI gates:
safenpm doctor --json
Lockfile (20% weight) — checks for missing lockfile, git/file dependencies, missing integrity hashes, weak algorithms, and staleness.
Install Scripts (25% weight) — static analysis of all postinstall hooks. Critical-risk scripts heavily penalize the score.
Typosquats (20% weight) — scans every package name. A single high-confidence typosquat drops this section to 10/100.
Reputation (15% weight) — aggregate reputation score from all packages. Low-reputation packages (missing license, no repo, single maintainer) drag this down.
Behavior (10% weight) — compares install scripts against cached baselines. Significant risk increases are flagged.
Project Hygiene (10% weight) — checks for .safenpmrc, engines field, wildcard version ranges, and package.json health.
A+ (97+), A (93+), A- (90+), B+ (87+), B (83+), B- (80+), C+ (77+), C (73+), C- (70+), D (60+), F (below 60). Doctor exits non-zero on D or F for CI gating.
Every finding includes a fix: suggestion — specific commands to run,
config changes to make, or packages to replace. If auto-fixable issues are found, doctor
prompts you to run safenpm fix.
safenpm fix scans for fixable issues and applies corrections automatically.
# Preview what would be fixed:
safenpm fix --dry-run
# Apply all fixes:
safenpm fix
# JSON output:
safenpm fix --json
Typosquat replacement — high and medium confidence typosquats are automatically
removed and replaced with the legitimate package. For example, axois
gets uninstalled and axios gets installed in its place.
Malicious package removal — packages that were blocked during
safenpm install (network or filesystem violations) can be
removed from node_modules and package.json in one step.
Fix uses npm uninstall to cleanly remove packages, then
npm install --ignore-scripts for replacements. If npm uninstall
fails (corrupted state), it falls back to manual cleanup: deleting the directory from
node_modules and stripping the entry from all dependency fields in package.json.
safenpm diff shows exactly what changed in your dependencies
since the last time you took a snapshot — like git diff for your node_modules.
# Save current state as baseline:
safenpm diff --snapshot
# After updating packages, see what changed:
npm update
safenpm diff
# JSON output:
safenpm diff --json
Install script changes — line-level diffs of postinstall/preinstall hooks with red/green coloring. Shows when scripts are added, removed, or modified between versions.
Dependency changes — new dependencies added, old ones removed, and version range changes within each package.
File changes — new files added or removed from the package directory. Catches when a package ships unexpected new binaries or scripts.
Run safenpm diff --snapshot after a clean install to establish
your baseline. Then after any npm update or version bump, run
safenpm diff to review changes before deploying. Integrate into
CI by checking the JSON output for unexpected script modifications.
One command. Zero configuration. Full protection.
npm install -g @abgunaydin/safenpm See what safenpm catches →