LmCast :: Stay tuned in

Show HN: Safe-NPM – only install packages that are +90 days old

Recorded: Nov. 27, 2025, 1:02 a.m.

Original Summarized

GitHub - kevinslin/safe-npm: Safely install NPM packages

Skip to content

Navigation Menu

Toggle navigation

Sign in

Appearance settings

Platform

GitHub Copilot

Write better code with AI

GitHub Spark


New

Build and deploy intelligent apps

GitHub Models


New

Manage and compare prompts

GitHub Advanced Security

Find and fix vulnerabilities

Actions

Automate any workflow

Codespaces

Instant dev environments

Issues

Plan and track work

Code Review

Manage code changes

Discussions

Collaborate outside of code

Code Search

Find more, search less

Explore

Why GitHub

Documentation

GitHub Skills

Blog

Integrations

GitHub Marketplace

MCP Registry

View all features

Solutions

By company size

Enterprises

Small and medium teams

Startups

Nonprofits

By use case

App Modernization

DevSecOps

DevOps

CI/CD

View all use cases

By industry

Healthcare

Financial services

Manufacturing

Government

View all industries

View all solutions

Resources

Topics

AI

DevOps

Security

Software Development

View all

Explore

Learning Pathways

Events & Webinars

Ebooks & Whitepapers

Customer Stories

Partners

Executive Insights

Open Source

GitHub Sponsors

Fund open source developers

The ReadME Project

GitHub community articles

Repositories

Topics

Trending

Collections

Enterprise

Enterprise platform

AI-powered developer platform

Available add-ons

GitHub Advanced Security

Enterprise-grade security features

Copilot for business

Enterprise-grade AI features

Premium Support

Enterprise-grade 24/7 support

Pricing

Search or jump to...

Search code, repositories, users, issues, pull requests...

Search

Clear

Search syntax tips

Provide feedback


We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.
You signed out in another tab or window. Reload to refresh your session.
You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

kevinslin

/

safe-npm

Public

Notifications
You must be signed in to change notification settings

Fork
0

Star
20

Safely install NPM packages

20
stars

0
forks

Branches

Tags

Activity

Star

Notifications
You must be signed in to change notification settings

Code

Issues
0

Pull requests
0

Actions

Projects
0

Security

Uh oh!

There was an error while loading. Please reload this page.


Insights

Additional navigation options

Code

Issues

Pull requests

Actions

Projects

Security

Insights

kevinslin/safe-npm

 mainBranchesTagsGo to fileCodeOpen more actions menuFolders and filesNameNameLast commit messageLast commit dateLatest commit History4 Commitssrcsrc  testtest  .cursorindexingignore.cursorindexingignore  .gitignore.gitignore  README.mdREADME.md  TODO.mdTODO.md  package-lock.jsonpackage-lock.json  package.jsonpackage.json  tsconfig.jsontsconfig.json  vitest.config.tsvitest.config.ts  View all filesRepository files navigationREADMEsafe-npm
A security-focused npm installer that protects your projects from newly compromised packages.
Why does this exist?
Supply chain attacks on npm packages are a growing threat. Attackers sometimes compromise legitimate packages by:

Stealing maintainer credentials
Publishing malicious updates to popular packages
Taking over abandoned packages

These attacks often happen suddenly—a package that was safe yesterday might be compromised today. safe-npm protects you by only installing package versions that have been publicly available for a minimum amount of time (90 days by default). This gives the security community time to discover and report malicious releases before they reach your project.
How it works
When you run safe-npm install, it:

Reads your dependencies from package.json or command-line arguments
Queries the npm registry to find all available versions
Filters out versions published more recently than your minimum age threshold
Selects the newest version that meets both your semver requirements AND age requirements
Installs the safe versions using npm

For example, if you specify react@^18 and a malicious react@18.5.0 was published yesterday, safe-npm will install the latest version that's at least 90 days old instead.
Installation
Install from npm (recommended)
# Install globally
npm install -g @dendronhq/safe-npm

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

# Link the binary globally
npm link
Basic usage
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
Dry run to see what would be installed
# Preview which versions would be installed without actually installing
safe-npm install --dry-run
Configuration options
--min-age-days <n>
Default: 90
The minimum number of days a package version must have been published before it can be installed.
Example: --min-age-days 120 requires packages to be at least 4 months old.
When to adjust:

Increase for maximum security (e.g., 180 days for critical production systems)
Decrease if you need newer features and accept slightly more risk (e.g., 30 days)

--ignore <pkg1,pkg2>
A comma-separated list of packages that bypass the age requirement. These packages will still respect semver ranges but ignore the minimum age.
Example: --ignore typescript,@types/node
When to use:

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

--strict
Exit with an error if ANY dependency cannot be resolved to a version meeting the age requirement.
Example: safe-npm install --strict
When to use:

CI/CD pipelines where you want builds to fail rather than skip problematic packages
Production deployments where you need certainty

--dev / --prod-only
Control which dependencies from package.json are processed.
Examples:

safe-npm install --dev - Only install devDependencies
safe-npm install --prod-only - Only install production dependencies

When to use:

Installing development tools with stricter requirements
Production builds where you want different age policies for dev vs prod dependencies

--strategy <direct|overrides>
Default: direct
How safe-npm installs the resolved versions:
direct - Directly installs the resolved versions using npm install package@version

Simple and straightforward
Good for one-time installs or scripts

overrides - Writes resolved versions to package.json overrides field, then runs npm install

Enforces versions across your entire dependency tree (including transitive dependencies)
Note: This feature is currently disabled as it doesn't work correctly yet

--registry <url>
Default: https://registry.npmjs.org
Specify an alternate npm registry.
Example: --registry https://registry.company.com
When to use:

Private npm registries
Mirrors or caches

--dry-run
Show what would be installed without making any changes.
Example: safe-npm install --dry-run
When to use:

Testing your configuration
Understanding what versions are available
Before making changes to production systems

Common workflows
Secure a new project
# 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
CI/CD integration
# 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
Emergency updates
# Need to urgently update a specific package? Add it to ignore list
safe-npm install --ignore package-with-critical-fix
Testing
The project includes a test suite that you can run:
npm test
For automated testing, you can mock registry responses using fixtures:
export SAFE_NPM_FIXTURES=/path/to/fixtures.json
safe-npm install
The fixtures file should contain JSON that mirrors npm registry responses for each package.
How this protects you
Real-world scenario:

A popular package popular-lib is maintained by a trusted developer
Attacker compromises the maintainer's npm credentials
Attacker publishes popular-lib@5.0.0 with malware
Projects using ^5.0.0 would immediately install the malicious version
With safe-npm, you'd keep using 4.9.0 (the latest version from 90+ days ago)
Security researchers discover the compromise and report it
The malicious version is unpublished
You never installed the compromised version

Limitations

Won't protect against packages that were malicious from the start
Delays access to legitimate new features and bug fixes
Requires trust that older versions don't have undiscovered vulnerabilities
Age-based filtering is a heuristic, not a guarantee

Philosophy
Security is about trade-offs. safe-npm trades bleeding-edge updates for protection against sudden supply chain compromises. It's one layer in a defense-in-depth strategy that should also include:

Regular security audits (npm audit)
Dependency review before adding new packages
Monitoring for security advisories
Using lock files to ensure reproducible builds
Running in sandboxed or containerized environments

Requirements

Node.js 18 or higher
npm (for the underlying installation)

License
ISC

About

Safely install NPM packages

Resources

Readme

Uh oh!

There was an error while loading. Please reload this page.


Activity
Stars

20
stars
Watchers

0
watching
Forks

0
forks

Report repository

Releases
No releases published

Packages
0

No packages published

Languages

TypeScript
51.3%

JavaScript
48.7%

Footer

© 2025 GitHub, Inc.

Footer navigation

Terms

Privacy

Security

Status

Community

Docs

Contact

Manage cookies

Do not share my personal information

You can’t perform that action at this time.

safe-npm is a security-focused npm installer designed to mitigate the rising threat of supply chain attacks on Node.js projects. The core functionality centers around selectively installing npm packages based on their publication age, providing a defense mechanism against quickly-deployed, potentially malicious updates. This summary will detail its operation, configuration options, and intended usage.

The project’s rationale stems from the increasing risk of compromised npm packages. Attackers can exploit compromised maintainer credentials or inject malware into widely-used packages. The attacker can, for example, take over an abandoned package or publish malicious updates. The key benefit of safe-npm is that it prevents projects from immediately installing these newly-compromised versions by filtering packages based on how long they have been publicly available. The default age threshold is 90 days, intended to grant the security community sufficient time to discover and report malicious releases. This delay is critical in reducing the window of vulnerability.

How it Works:

At its most basic, `safe-npm install` operates by reading the dependency list from your `package.json` file (or provided command-line arguments). It then queries the npm registry for all available versions of those dependencies. Critically, it filters those versions based on their publication age in relation to the configured minimum age. The new version that is both semantically compatible (as defined by your version constraints—e.g., `^18` for React) and at least 90 days old is selected and installed using npm. The output is stored in the package-lock.json, ensuring consistent builds. A dry-run feature allows a preview of what would be installed without making any changes.

Configuration Options:

* `--min-age-days <n>`: This is the primary configuration option, specifying the minimum number of days a package version must have been publicly available before it can be installed. The default value is 90 days, but can be adjusted based on project criticality and risk tolerance. Raising this value enhances security but might delay access to new features or bug fixes. Reducing this value balances risk and expediency.
* `--ignore <pkg1,pkg2>`: This allows you to bypass the age requirement for specific packages. These packages are still subject to semver constraints but are not filtered based on their age. This is useful for fast-moving dependencies like TypeScript or build tools, where delaying updates might be detrimental.
* `--strict`: When enabled, `safe-npm install` will exit with an error if *any* dependency cannot be resolved to a version meeting the age requirement. This promotes a more defensive posture, ensuring that no project silently installs potentially vulnerable packages.
* `--strategy <direct|overrides>`: (Currently disabled, but designed for): This option, when enabled, would ensure that versions are written to package.json's overrides field and then install them, which enforces a consistent dependency tree across your entire project. This is a more advanced feature that is currently not fully functional.
* `--registry <url>`: This allows you to specify an alternate npm registry, such as a private registry or a mirror.
* `--dry-run`: Outputs what would be installed without actually making changes to your project's dependencies. This is useful for testing your configuration before executing a full `safe-npm install`.

Intended Workflows:

* Secure a New Project: When starting a new project, `safe-npm install` ensures that all dependencies are initially compliant with age requirements.
* Audit an Existing Project: Run `safe-npm install --dry-run` to preview potential changes and assess the age of existing dependencies. Subsequently, install the confirmed safe versions.
* CI/CD Integration: Implement `safe-npm install --strict` in a CI/CD pipeline to automatically fail builds if dependencies cannot meet age requirements, minimizing the risk of deploying vulnerable software.
* Emergency Updates: Quickly install a patched version or fix for a critical package by adding it to the ignored list with `--ignore`.

Limitations:
Safe-npm is not a perfect solution. It primarily defends against packages that are immediately compromised. It does not protect against packages that have been maliciously maintained from the outset. There is a delay in access to new features and bug fixes. The age-based filtering is a heuristic; it does not guarantee complete protection from undiscovered vulnerabilities.

Philosophy:

The development of safe-npm reflects a trade-off between security and expediency. The tool prioritizes protection against sudden supply chain compromises while acknowledging the potential for delayed feature access and bug fixes. It is one layer within a broader defense-in-depth strategy. The project also includes recommendations as a best practice for security: regular security audits (npm audit) , dependency review before adding new packages, monitoring for security advisories, using lock files, and using sandboxed or containerized environments.

It's crucial to recognize that safe-npm isn't a silver bullet but a valuable addition to a thorough software security strategy.