Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@kushankurdas/npm-sentinel) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
npm-sentinel
npm-sentinel helps you catch risky dependency changes before or during install:
- Fast checks — scan your
package-lock.jsonagainst vulnerability databases and known-bad versions. - Baseline drift — detect new dependencies or install scripts on packages you trust (similar to how the Axios supply-chain incident introduced a hidden dependency).
- Optional Docker sandbox — run
npm ciinside a container with DNS monitoring, so maliciouspostinstallscripts do not run on your host during that check.
Simple guide: two jobs, five commands
Think of it as two layers:
| Layer | What it does | Needs Docker? |
|---|---|---|
| A — Static | Reads the lockfile, calls OSV, optional baseline compare | No |
| B — Sandbox | Runs a real npm ci in Linux + watches DNS |
Yes |
Cheat sheet (what to run)
| I want… | Command |
|---|---|
| Quick “is my lockfile bad?” (daily / CI) | npx npm-sentinel check |
| Same + compare to a saved “good” snapshot | npx npm-sentinel check --baseline |
| Save a “good” snapshot (commit the file afterward) | npx npm-sentinel baseline save |
| See what changed vs that snapshot | npx npm-sentinel baseline diff |
| Heavy: install in Docker + DNS allowlist | npx npm-sentinel sandbox |
| CI: static check, then optionally sandbox | npx npm-sentinel gate or npx npm-sentinel gate --require-sandbox |
Most teams: use check (and check --baseline once baselines exist) on every PR; add sandbox where you need install-time behavior proof.
Commands in plain English
check— “Does this lockfile list any known vulnerable or known-malicious versions?” Optionally: “Did my trusted direct deps drift vs my baseline?”baseline save— “Remember today’s dependency + script picture for my rootpackage.jsondeps as trusted.” Writes.npm-sentinel-baseline.json.baseline diff— “What changed sincebaseline save?” (new child deps, new install scripts, version bumps, etc.)sandbox— “Copy the project into a container, runnpm ciwith scripts on, record DNS. Fail if DNS hits unknown domains ornpm cifails.” Use--mount-sshif you have privategit+sshdependencies (see below).gate— “Runcheckwith baseline diff enabled if a baseline file exists. With--require-sandbox, runsandboxaftercheckpasses.”
Quick start
1. In any repo that has package-lock.json
cd your-project
npx npm-sentinel checkExit code 0 = no findings at your severity threshold; 1 = findings or baseline errors.
2. Optional: block install on bad lockfile (host only runs static check)
Use npx or a global install so preinstall works on a fresh clone:
{
"scripts": {
"preinstall": "npx --yes npm-sentinel@latest check --baseline"
}
}Static preinstall does not run dependency postinstall on the host if npm aborts first. For install-time behavior, use sandbox separately or in CI.
3. Optional: baseline workflow
npx npm-sentinel baseline save
git add .npm-sentinel-baseline.json
git commit -m "chore: npm-sentinel baseline"Later:
npx npm-sentinel check --baseline4. Optional: Docker sandbox (git+ssh private deps)
npx npm-sentinel sandbox --mount-sshOr a folder with only deploy keys:
npx npm-sentinel sandbox --ssh-dir /path/to/keysSee Docker & SSH below for macOS vs Linux caveats.
Install
npm install -D npm-sentinelnpm install -g npm-sentinelFrom a local clone of this repo:
cd npm-sentinel
npm link
cd /path/to/your-app
npm link npm-sentinelRequirements
- Node.js ≥ 18
- Docker — only for
sandboxandgate --require-sandbox package-lock.jsonat the project root (required forcheck,baseline,sandbox)
Command reference (detailed)
| Command | Description |
|---|---|
npm-sentinel check |
Lockfile → OSV + offline IOCs; add --baseline if .npm-sentinel-baseline.json exists |
npm-sentinel baseline save |
Write baseline from lockfile + registry metadata for watched packages |
npm-sentinel baseline diff |
Print drift vs baseline |
npm-sentinel sandbox |
Docker: copy project, npm ci, tcpdump DNS vs allowlist |
npm-sentinel gate |
check with baseline diff; --require-sandbox runs sandbox after |
npm-sentinel help |
Print help |
Flags
| Flag | Purpose |
|---|---|
--cwd <dir> |
Project root (default: current directory) |
--json |
JSON output |
--min-severity |
low | moderate | high | critical (default: low) |
--no-osv |
Skip OSV API |
--offline |
Skip OSV (offline IOCs still apply) |
--baseline |
With check, run baseline diff when baseline file exists |
--npm-audit |
Also run npm audit --json |
--require-sandbox |
With gate, run sandbox after check |
--no-build |
sandbox: reuse existing Docker image |
--mount-ssh |
sandbox: mount host ~/.ssh read-only at /root/.ssh |
--ssh-dir <path> |
sandbox: mount this directory instead of ~/.ssh |
--baseline-file <path> |
Alternate baseline file path |
Docker sandbox and your machine
- The sandbox runs Linux in Docker. It does not always give you a macOS/Windows–usable
node_moduleswhen packages ship native binaries built for your host OS. - Recommendation: run
sandboxin CI (Linux); locally usecheck, or develop inside a Dev Container if you want Linuxnode_modulesdaily.
Private git+ssh dependencies
The image includes git and openssh-client.
| Approach | Command / config |
|---|---|
| Mount host keys | npm-sentinel sandbox --mount-ssh |
| Mount a key folder only | npm-sentinel sandbox --ssh-dir /path/to/keys |
| Config file | npm-sentinel.config.json: "sandbox": { "mountSsh": true } or "sshDir": "/path" |
macOS: Your ~/.ssh/config may use UseKeychain, which Linux OpenSSH does not support. The tool sets GIT_SSH_COMMAND with -F /dev/null so the mounted config is ignored; default key files in the mount still apply (id_ed25519, id_rsa, …). Keys that exist only in the Keychain and not on disk may still fail — use a deploy key file or git+https with a token in CI.
Security: Mounting ~/.ssh gives the container read access to whatever keys are in that directory. Prefer deploy keys or HTTPS + token for automation.
Configuration
Create npm-sentinel.config.json or .npm-sentinelsrc.json in the project root:
{
"watchPackagesExtra": ["some-transitive-parent"],
"watchPackagesOverride": null,
"dnsAllowlist": {
"mode": "merge",
"suffixes": ["my-registry.example.com"],
"exactHosts": []
},
"sandbox": {
"mountSsh": true
}
}| Key | Meaning |
|---|---|
| Watched packages | Defaults to root dependencies + devDependencies (+ optional peers / optionals). watchPackagesExtra adds more parent names. |
watchPackagesOverride |
If set (array), only these names are watched (replaces default list + extras). |
dnsAllowlist |
DNS allowlist for sandbox: mode merge (default) adds suffixes / exactHosts to the built-in list; replace uses only your lists (strict; you must include every host your install needs). |
sandbox.mountSsh |
Same as --mount-ssh. |
sandbox.sshDir |
Same as --ssh-dir (wins over mountSsh when set). |
Baseline signals
When you compare to a saved baseline, npm-sentinel can report:
- New direct dependencies on a watched package (dependency injection)
- New lifecycle scripts on a resolved version (
preinstall/install/postinstall) - Version changes on watched packages
- Removed dependencies (warning; can be noisy; possible account-takeover signal)
Development (this repo)
Command details and testing: docs/ (per-command guides under docs/commands/). Security reports: SECURITY.md.
git clone https://github.com/kushankurdas/npm-sentinel.git
cd npm-sentinel
npm ci
npm testIf your GitHub username or repo name differs, update the repository, bugs, and homepage fields in package.json to match.
Related reading
- pakrat — behavioral npm monitoring (inspiration)
- Elastic — Axios supply chain
- Microsoft — Axios mitigation