Installing one NPM package can introduce transitive dependencies and execute lifecycle scripts before your application starts. The official npm package.json documentation defines those dependency fields and lifecycle commands. Popularity helps discovery, but download count is not a security boundary.
The manual review
- Confirm identity. Check the exact package name for typosquatting, the registry owner, repository link, maintainers, publication history, funding or organizational backing, and whether ownership recently changed.
- Choose the exact version. Review the version you plan to lock, not merely the latest branch. Record integrity information and release dates.
- Inspect package metadata. Read package.json, entry points, exports, engines, bundled files, dependency ranges, peer dependencies, license, and preinstall, install, postinstall, prepare, and build scripts. The npm metadata reference is the definition, not a third-party summary.
- Compare source and artifact. Download the published tarball and compare its contents with the repository tag or documented build output. Check for a verified npm provenance statement when one is available. SLSA defines provenance as verifiable information about where, when, and how an artifact was produced.
- Review direct and transitive risk. Inventory dependency coverage, known advisories, malware reports, deprecated packages, maintainer concentration, suspicious lookalikes, and deeply permissive version ranges. Record when intelligence is partial or unavailable.
- Read the security-sensitive code. Focus on authentication and authorization, data protection, injection, command and file operations, network access, cryptography, error handling, configuration, dynamic execution, and third-party components. NIST SP 800-218 provides a useful baseline for secure development and artifact integrity.
- Exercise it safely. Install in an isolated environment, observe file and network behavior, and run the project's tests. Do not execute untrusted lifecycle scripts on a privileged workstation.
- Plan updates and exit. Define who can approve upgrades, how alerts are monitored, how quickly the package can be replaced, and what would trigger reassessment.
The repository is not the package
A GitHub repository is evidence about a project. Your application executes the files published in the registry tarball. Those two things may correspond perfectly, but the repository link on an npm page does not establish that relationship by itself.
Start with the exact version you intend to install. Use npm's package-download or packing workflow without executing the package, list the tarball contents, and compare them with the corresponding source tag and documented build output. Pay attention to files selected through the package metadata, generated bundles, minified code, native binaries, source maps, and code that exists in the package but not in the repository. A difference may be a normal build artifact. It still needs an explanation.
Provenance can improve this evidence chain. npm's provenance documentation describes how supported publishing workflows attach verifiable statements, and SLSA provenance describes the information used to connect an artifact with its build process. Provenance does not review the source for you. It helps answer whether the artifact came from the source and build you meant to review.
Lifecycle scripts change the trust boundary
A library normally becomes risky when your application imports or calls it. A package with install-time scripts can act earlier. The package.json specification identifies script fields and dependency metadata that influence installation and execution. Review what the selected package and its dependencies can run during install, prepare, build, test, and publication.
The practical questions are plain: Does the script spawn a shell, download another executable, inspect environment variables, modify files outside the package directory, compile native code, or contact an undocumented host? Does it behave differently in continuous integration? Could it see registry tokens, cloud credentials, signing keys, or production secrets present in the build environment? If you cannot answer safely, inspect in a disposable environment with no reusable credentials and with network behavior observable.
Do not confuse the existence of a script with maliciousness. Native modules need compilation. Projects generate platform-specific code. The control is understanding why the script exists, constraining what it can reach, and deciding whether the package's value justifies that capability.
A worked decision: the convenient document converter
A development team proposes a package that converts office documents into preview images. It has millions of weekly downloads, clear documentation, and a permissive license. A quick advisory scan reports no known vulnerabilities. That sounds reassuring, but none of those facts describes what will run during installation.
The exact tarball includes a postinstall script. The script detects the operating system and downloads a platform-specific binary from the project's release host. The repository contains the JavaScript wrapper, but the downloaded binary is not part of the npm tarball and is not built by the application's normal pipeline. The package therefore introduces a second artifact, a network dependency, and another update path.
The review now asks better questions. Are release checksums or signatures published? Can the binary be mirrored and pinned? Is the release host controlled by the same maintainers? Does a provenance statement cover only the npm package or also the binary? What privileges will the converter have when it processes attacker-supplied documents? Could the application replace the package with a containerized system tool that is patched through an existing process?
Suppose the business needs previews, the package saves months of engineering work, and the application already processes uploads in an isolated worker with no production credentials. Conditional approval may be reasonable: pin the npm version and binary checksum, mirror the binary internally, disable outbound network access at runtime, scan sample documents in the isolated worker, monitor the upstream project, and reassess when either artifact changes. If the build cannot pin the downloaded binary, the status stays pending. Popularity did not make the decision. Evidence and deployment context did.
Place the package in its business context
Document where it runs, the secrets and data it can access, whether it executes during build or production, its network reach, the applications depending on it, compensating controls, and the owner accepting residual risk. A development-only formatter and a production authentication library should not receive the same review.
Signals are not verdicts
A small maintainer group is not proof of danger. A high download count is not proof of safety. An old package may be stable or abandoned. A recent release may be healthy or compromised. Combine signals with actual code, artifact, dependency, advisory, and provenance evidence.
Interpret advisories in the path that actually runs
An advisory is not a complete deployment decision. Confirm the affected package and version, the vulnerable behavior, whether your application reaches that behavior, the privileges and data available at that point, and whether a fix or mitigating control exists. The CISA Known Exploited Vulnerabilities Catalog is especially useful when it identifies vulnerabilities with evidence of exploitation, but package review still needs version and reachability analysis.
The reverse is equally important. "No advisories found" means the sources you queried did not return a matching record for the inventory they received. It does not prove the inventory is complete, that the package contains no unknown vulnerability, or that application-specific logic is safe. Record which ecosystems and dependency layers were covered, which lookups failed, and whether bundled or downloaded components were visible to the scanner.
You cannot deeply review every dependency
Correct. Prioritize packages with lifecycle scripts, native code, credential or filesystem access, network behavior, central architectural roles, weak provenance, or high transitive reach. Use locks, allowlists, isolated builds, least privilege, and continuous monitoring to contain what manual review cannot cover.
Record the dependency coverage you actually achieved
A package manifest describes requested dependency ranges. A lockfile records the versions resolved for a particular dependency graph and package-manager workflow. Preserve both when available, along with the package-manager version and the platform used for resolution. Optional, peer, bundled, development, and platform-specific dependencies can change what appears in the installed tree, so a single top-level package name is not a complete inventory.
When tools disagree, keep the disagreement visible. One scanner may analyze the lockfile, another may inspect the installed tree, and another may query only direct dependencies. Record the input each tool received, failed lookups, unsupported ecosystems, and the time of the advisory check. This lets a later reviewer distinguish "no matching advisories" from "the dependency was never examined." The inventory is also the starting point for monitoring after approval, because a review frozen on approval day cannot warn you about an advisory published next week.
Record the package and deployment decision
The source-readable software workbook covers source and artifact identification, provenance, lifecycle hooks, dependencies, network and data behavior, security controls, licensing, conditions, human approval, and reassessment.
Sources and further reading
Managing repeated package reviews
Can I Run That? can organize package analysis, dependencies, advisories, provenance, evidence, and review history across many requests. Reviewers still investigate material signals and make the deployment decision.