
Static security analysis for npm packages. Detects obfuscated code, malicious patterns, and known vulnerabilities before installation.

Static security analysis for npm packages — detects obfuscated lifecycle scripts, known vulnerabilities, and malicious patterns before they run. Drop-in replacement for npm install and npm ci.
Zero dependencies. Pure Node.js built-ins only. < 100 kB on the wire.
npx np-audit scan express
npm install -g np-audit
npa scan # scan all deps
npa install # audit then install
alias npm='npa' # use as drop-in replacement
Detection is split into modular marshallers — each one detects a single attack signal:
| Marshaller | What it detects | Score |
|---|---|---|
eval/dynamic-exec | eval(), new Function(), indirect eval, vm.*, setTimeout with string | 8 |
obfuscator.io | _0x variable naming patterns (obfuscator.io output) | 9–80 |
high-entropy-string | Long strings or concatenation chains with high Shannon entropy | 6 |
hex-escape-density | Dense \xNN and \uXXXX escape sequences | 5–50 |
fromCharCode | String.fromCharCode with many args, large decimal char-code arrays | 7 |
encoded-decode | Base64/hex decode (atob, Buffer.from) optionally combined with eval | 3–8 |
child-process | require('child_process'), exec, spawn, fork, worker_threads | 5 |
hex-array | Large numbers of 0x hex literal values | 7–60 |
process-env | process.env access (credential exfiltration signal) | 3 |
network-call | require('https'), fetch(), dns, net, tls | 4 |
filesystem-manipulation | fs.writeFile, chmod, symlink (backdoor persistence) | 3–4 |
runtime-download | Downloads and executes external runtimes (Bun, Deno) | 9–50 |
vscode-autorun | VS Code tasks with runOn: folderOpen (auto-execution) | 30 |
known-vulnerability | Known CVEs via Snyk API or OSV.dev | 4–6 (WARN), 80 (malicious) |
Scores scale with severity — higher counts of obfuscation indicators produce higher scores. The final verdict is based on the highest individual score across all marshallers.
See CONTRIBUTING.md for how to write custom marshallers.
Every scanned package is checked against known vulnerability databases alongside the code analysis.
Default: OSV.dev (no setup required)
Works out of the box — queries the free OSV.dev API for known vulnerabilities and malicious package advisories.
Optional: Snyk API (richer data)
# Environment variable
export SNYK_API_TOKEN=your-token-here
# Or via Snyk CLI
snyk auth
Token resolution order: SNYK_API_TOKEN → SNYK_TOKEN → ~/.config/configstore/snyk.json
| Severity | Score | Verdict |
|---|---|---|
| Malicious package | 80 | DANGER |
| 10+ vulnerabilities | 6 | WARN |
| 5–9 vulnerabilities | 5 | WARN |
| 1–4 vulnerabilities | 4 | WARN |
Non-malicious CVEs produce warnings but never block installation. Only confirmed malicious packages trigger DANGER.
| Command | Alias | Description |
|---|---|---|
npa install [package] | npa i | Audit then run npm install |
npa ci | — | Audit then run npm ci |
npa scan [package] | npa s | Scan only, no install |
npa config get | npa c get | Show current configuration |
npa config set <key> <value> | npa c set | Update a config value |
npa alias --install | — | Install shell alias |
npa alias --uninstall | — | Remove shell alias |
Any unrecognized command is forwarded to npm (e.g. npa run test, npa publish).
| Flag | Alias | Works with | Description |
|---|---|---|---|
--review | -r | install, ci | Interactive mode — choose which scripts to allow |
--json | — | install, ci, scan | Machine-readable JSON output |
--no-dev | — | install, ci, scan | Skip devDependencies |
--verbose | — | all | Show fetch progress and extra detail |
--version | -v | — | Print version and exit |
--help | -h | — | Print help and exit |
--review modenpa install --review
npa --review mode
Use ↑/↓ to navigate, SPACE to toggle, ENTER to confirm, q to quit
Found 3 package(s) with install scripts:
[✓ allow] [email protected] postinstall: post-install.js OK
▶ [✗ deny ] [email protected] postinstall: install.js DANGER (score: 9)
[✓ allow] @scope/[email protected] postinstall: install.js WARN (score: 5)
2 allowed 1 denied
Config is stored in ~/.npmauditor.json (global) and can be overridden per project with .npmauditor.json.
npa config get # Show current config
npa config set blockScore 6 # Block at score 6+
npa config set skipPackages '["esbuild"]' # Trust specific packages
npa config set skipScopes '["@types"]' # Trust entire scopes