kevinslin/safe-npm: Safely install NPM packages

A security-focused NPM installer that protects your projects from new compromised packages.

Supply chain attacks on NPM packages are a growing threat. Attackers sometimes compromise legitimate packages:

  • stealing maintainer credentials
  • Publishing malicious updates to popular packages
  • Taking possession of abandoned packages

These attacks often occur suddenly—a package that was secure yesterday may be compromised today. secure-npm Protects you by only installing package versions that are publicly available for a minimum period of time (90 days by default). This gives the security community time to discover and report malicious releases before they reach your project.

when you run safe-npm installit:

  1. Reads your dependencies from package.json or command-line arguments
  2. Query the npm registry to find all available versions
  3. Filters editions published more recently than your minimum age limit
  4. Selects the latest version that meets both your semester requirements and age requirements
  5. Installs secure version using npm

For example, if you specify react@^18 and a malicious react@18.5.0 Published yesterday, secure-npm will instead install the latest version that is at least 90 days old.

Install from npm (recommended)

# Install globally
npm install -g @dendronhq/safe-npm

# Now you can use it anywhere
safe-npm install
# Clone and build
git clone <repository-url>
cd safe-npm
npm install
npm run build

# Link the binary globally
npm link

Install dependencies from package.json

# Use the minimum age of 90 days (default)
safe-npm install

# Or specify your own minimum age
safe-npm install --min-age-days 120

install specific packages

# Install packages directly with version constraints
safe-npm install react@^18 lodash@^4.17.0

# These will be filtered to only use versions at least 90 days old
safe-npm install express --min-age-days 60

Do a dry run to see what will be installed

# Preview which versions would be installed without actually installing
safe-npm install --dry-run

default: 90

The minimum number of days a package version must be published before it can be installed.

Example: --min-age-days 120 The package must be at least 4 months old.

When to adjust:

  • Increase for maximum protection (e.g., 180 days for critical production systems)
  • Do less and accept a little more risk if you need new features (for example, 30 days)

Comma-separated list of packages that bypass the age requirement. These packages will still respect the semester ranges but will ignore the minimum age.

Example: --ignore typescript,@types/node

When to use:

  • Fast-moving packages you rely on (like TypeScript or build tools)
  • Internal packages from your organization
  • Packages where you urgently need the latest features

Exit with an error if a dependency cannot be resolved to a version that meets the age requirement.

Example: safe-npm install --strict

When to use:

  • CI/CD pipeline where you want builds to fail instead of skipping problematic packages
  • Production deployment where you need certainty

Control which dependencies are package.json are processed.

Example:

  • safe-npm install --dev – Install only devdependencies
  • safe-npm install --prod-only – Install only production dependencies

When to use:

  • Setting up development tools with strict requirements
  • Production builds where you want different age policies for development vs. product dependencies

default: direct

How secure-npm installs resolved versions:

direct – Installs directly using resolved versions npm install package@version

  • simple and straightforward
  • Good for one-time installation or script

overrides – writes resolved versions package.json Overrides the field, then runs npm install

  • Applies versioning to your entire dependency tree (including variable dependencies)
  • Comment: This feature is currently disabled because it does not work properly yet

default: https://registry.npmjs.org

Specify an alternative npm registry.

Example: --registry https://registry.company.com

When to use:

  • private npm registries
  • mirror or cache

Show what will be installed without making any changes.

Example: safe-npm install --dry-run

When to use:

  • Your configuration is being tested
  • Understanding which versions are available
  • Before making changes to production systems
# Create a new project
mkdir my-project && cd my-project
npm init -y

# Install dependencies safely
safe-npm install express@^4 lodash

# This creates package-lock.json with versions at least 90 days old

Audit an existing project

# Check what versions would be installed with age requirements
safe-npm install --dry-run

# If you're happy, install them
safe-npm install
# In your CI pipeline, fail the build if any package can't meet age requirements
safe-npm install --strict --min-age-days 120

# Or allow newer packages for dev dependencies only
safe-npm install --prod-only --strict
# Need to urgently update a specific package? Add it to ignore list
safe-npm install --ignore package-with-critical-fix

The project includes a test suite that you can run:

For automated testing, you can mimic registry responses using fixtures:

export SAFE_NPM_FIXTURES=/path/to/fixtures.json
safe-npm install

The fixtures file should contain JSON that reflects the npm registry responses for each package.

Real World Scenario:

  1. a popular package popular-lib Maintained by a trusted developer
  2. Attacker compromises maintainer’s npm credentials
  3. the attacker publishes popular-lib@5.0.0 with malware
  4. using projects ^5.0.0 will immediately install the malicious version
  5. With secure-npm, you will continue to use 4.9.0 (Latest version 90+ days ago)
  6. Security researchers discover and report the compromise
  7. Malicious version is unreleased
  8. You have never installed a compromised version
  • Will not protect against packages that were malicious from the beginning
  • Delays access to legitimate new features and bug fixes
  • Requires confidence that older versions do not contain undiscovered vulnerabilities
  • Age-based filtering is a guess, not a guarantee

Security is about trade-offs. Safe-NPM trades state-of-the-art updates for protection from unexpected supply chain compromises. This is a layer in depth defense strategy that should also include:

  • Regular security audits (npm audit,
  • Review dependencies before adding new packages
  • monitoring for security advice
  • Using lock files to ensure reproducible builds
  • Running in a sandboxed or containerized environment
  • Node.js 18 or higher
  • npm (for implicit installation)

isc



<a href

Leave a Comment