npmpreflight
Audit a package directory before npm publish, while a bad publish is
still cheap to undo.
npmpreflight resolves the file set your package would actually ship,
scans the shipped files for secret patterns, totals the size, and checks
package.json for the fields and entry points a publish depends on. It
answers the questions that are embarrassing to discover after a release:
is a credential sitting in a shipped file, does the bin target exist
in the tarball, is the license field set, and is a scoped package about
to publish as restricted.
Install
Run it without installing:
Or install it globally:
Requires Node 20 or newer.
CLI usage
check [path] audits the package directory at path (default: the
current directory) and prints a human readable report. Add --json
for the machine readable report.
mcp starts the MCP server over stdio (see below).
--version prints the version.
Exit codes: 0 when the verdict is READY, 1 for any other verdict,
2 for a usage error or an unreadable or invalid package.json, and
141 when the reader closed the output pipe early.
Example output:
Findings never include the matched secret text. The evidence for a
secret finding is the pattern id only, plus the file and line, so a
report is safe to paste into an issue or a CI log.
MCP
The same audit is available as an MCP tool over stdio:
- Tool:
preflight_package
- Input:
path, the package directory to check
- Output: the JSON report, identical to
check --json
Start it with npmpreflight mcp, or configure an MCP client to run
npx @reneturcios/npmpreflight mcp. The server is also published as an
OCI image and listed in server.json under the name
io.github.CloudCorpRecords/npmpreflight.
Checks
Every report counts the shipped files and their total bytes, plus the
finding totals by severity.
Verdict
READY when there are no high severity findings. Medium, low, and
info findings are reported but do not block the verdict.
FIX-FIRST when at least one high severity finding exists.
How the shipped file set is resolved
- If
package.json has a files array, those paths are included:
files are added directly and directories are walked recursively.
package.json, README, and LICENSE are always included when
present, whether or not they are listed, matching npm.
- If there is no
files array, everything in the directory is included
except node_modules, .git, and paths matched by .npmignore
when one is present. The always included files above are still
included even if an ignore rule would match them.
- The walk is capped at 5000 shipped files. When the cap is reached
the report records it in its counts (
truncated: 1, with
filesSeen and maxFiles) and the render notes that the remaining
files were not scanned.
Limits
Read these before trusting a clean verdict:
- The file set is a static resolution, not a byte-exact
npm pack.
npm applies more rules (its own always excluded files, lifecycle
generated files, and publish time behaviour) that a static pass does
not reproduce. Treat npmpreflight as a preflight check, then confirm
a release with npm pack --dry-run.
.npmignore support is a simple subset: blank lines, # comments,
plain lines (a file name at any depth, or an exact relative path),
and directory patterns ending in /. Globs, negations, and
character classes in .npmignore are not supported and such lines
will not match the way npm would match them.
files entries support literal files, literal directories, simple
* and ** globs, and ! negations of those. Anything more exotic
is resolved literally and may differ from npm.
- Secret scanning reads text files only. A file whose scanned head
contains a NUL byte is treated as binary and skipped. Only the first
512 KiB of each file is scanned, so a secret past that offset in a
large file will not be found. Patterns are shapes, not proof: a
match can be a test fixture or an example, and a real credential in
an unrecognized shape will not match.
- Symlinks are not followed and are not shipped.
- Output is deterministic: findings are sorted, counts are stable,
and no timestamps are emitted.
Development
License
MIT