Package Exports
- package-age-guard
- package-age-guard/package.json
Readme
Package Age Guard
Block npm packages that are too new. Protect your projects against supply chain attacks.
Why?
Attackers sometimes publish malicious packages and rely on developers installing them immediately. By requiring packages to be at least 7 days old (configurable), you give the community time to discover and report malicious packages.
Real incidents this would have prevented:
- colors (Jan 2022) - Malicious version live for hours
- node-ipc (Mar 2022) - Protestware published and quickly installed
- typosquatting attacks - Fake packages with similar names
What's New in v1.2.0
๐ Major release with powerful new features:
- ๐ฏ Safe Version Suggestions - Get compliant older versions suggested automatically
- ๐ง Auto-Fix Mode - Install safe versions with
--fix - ๐ฎ Interactive Mode - Guided resolution with
--interactive - ๐งถ pnpm Support - Automatic protection during
pnpm install - ๐ GitHub Action - Official CI/CD integration
- ๐ฆ GitHub Release - Latest release badge in README
Installation
# Use with npx (no install required)
npx package-age-guard
# Or install globally
npm install -g package-age-guard
package-age-guard
# Short alias
npx pagQuick Start
# Check all dependencies (default: 7 day minimum)
npx package-age-guard
# Require 30 days minimum
npx package-age-guard --min=30
# Check production dependencies only
npx package-age-guard --production
# Show safe version suggestions
npx package-age-guard --suggest
# Auto-fix violations (install safe versions)
npx package-age-guard --fix
# Interactive mode - choose fixes manually
npx package-age-guard --interactive
# Output as JSON for CI
npx package-age-guard --jsonCLI Usage
๐ฆ Package Age Guard v1.1.0
Block npm packages that are too new - protect against supply chain attacks
Usage: npx package-age-guard [options]
Options:
--min=<days> Minimum package age (default: 7)
--production Check production dependencies only
--json Output results as JSON
--strict Exit with error on warnings too
--quiet, -q Minimal output
--verbose, -V Show detailed output
--suggest, -s Show safe version suggestions for violations
--fix, -f Auto-install suggested safe versions
--interactive, -i Interactive mode to choose fixes
--dry-run Show what would be done (with --fix)
--init Create .package-age-guard.json config file
--help, -h Show this help
--version, -v Show version
Exit codes:
0 All packages meet age requirements
1 One or more packages are too new (or warnings in strict mode)
2 Configuration or system errorConfiguration File
Create .package-age-guard.json in your project root:
{
"minAge": 30,
"productionOnly": false,
"whitelist": [
"my-internal-package",
"emergency-patch@1.2.3"
],
"failOnWarning": false,
"ignorePatterns": ["*", "latest", "next", "beta", "alpha", "rc", "canary"]
}Or add to your package.json:
{
"package-age-guard": {
"minAge": 14,
"productionOnly": false,
"whitelist": []
}
}Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
minAge |
number | 7 | Minimum package age in days |
productionOnly |
boolean | false | Check production deps only |
whitelist |
string[] | [] | Packages to skip (name or name@version) |
failOnWarning |
boolean | false | Treat warnings as failures |
ignorePatterns |
string[] | ['*', 'latest'] | Version patterns to skip |
pnpmMode |
string | 'warn' | pnpm hook mode: 'warn', 'error', or 'allow' |
Programmatic API
Use in your Node.js scripts:
import { checkPackages, loadConfig, formatResults } from 'package-age-guard';
// Check with default config
const results = await checkPackages();
console.log(formatResults(results));
// Check with custom config
const results = await checkPackages({
config: {
minAge: 30,
productionOnly: true,
whitelist: ['my-package']
}
});
// Load config from file
const config = await loadConfig();
console.log(`Min age: ${config.minAge} days`);API Methods
checkPackages(options)
Check all packages in a project.
Parameters:
options.cwd(string): Working directory (default: process.cwd())options.config(object): Configuration objectoptions.includeSuggestions(boolean): Include safe version suggestions for violations
Returns: Promise
{
passed: [{ name, version, age, published, status }],
violations: [{
name, version, age, published, status,
suggestion: { version, published, ageDays } // If includeSuggestions: true
}],
warnings: [{ name, version, age, reason, status }],
errors: [{ name, version, error, code, status }],
total: number,
minAge: number,
checkedAt: string
}getSafeVersion(packageName, minAge)
Find the latest version of a package that meets the minimum age requirement.
Parameters:
packageName(string): Package nameminAge(number): Minimum age in days (default: 7)
Returns: Promise<{version, published, ageDays} | null>
const safeVersion = await getSafeVersion('axios', 30);
// Returns: { version: '1.6.8', published: '2022-01-15T...', ageDays: 892 }loadConfig(cwd)
Load configuration from .package-age-guard.json or package.json.
Parameters:
cwd(string): Working directory (default: process.cwd())
Returns: Promise
formatResults(results)
Format check results as human-readable text.
Parameters:
results(CheckResults): Results from checkPackages()
Returns: string
hasViolations(results)
Check if results contain violations.
Returns: boolean
shouldFail(results, config)
Determine if check should fail based on results and config.
Returns: boolean
Safe Version Suggestions
When a package is too new, Package Age Guard can suggest a safe, older version that's been around long enough:
$ npx package-age-guard --suggest
๐ฆ Package Age Guard Results
Checked 15 packages (min age: 7 days)
...
โ axios@1.7.0 - Only 2 days old
๐ก Suggested: axios@1.6.8 (892 days old)
Install: npm install axios@1.6.8
...
๐ Security Policy Violation
1 package(s) are newer than 7 days.
These may be supply chain attack vectors.
Options:
1. Wait for packages to age
2. Use older versions (see suggestions above)
3. Install all suggested: npx package-age-guard --fix
4. Add to whitelist in .package-age-guard.jsonAuto-Fix Mode
Automatically install the suggested safe versions:
# Preview what would be changed (dry run)
npx package-age-guard --fix --dry-run
# Actually install safe versions
npx package-age-guard --fixThis will:
- Check all packages
- Find violations
- Look up safe versions
- Install them automatically
Interactive Mode
For more control, use interactive mode to choose how to handle each violation:
$ npx package-age-guard --interactive
๐ฎ Interactive Mode - 2 violation(s) to resolve
โ axios@1.7.0 - Only 2 days old
๐ก Suggested: 1.6.8 (892 days old)
Options:
s - Skip (do nothing)
i - Install suggested version (1.6.8)
w - Add to whitelist (this package)
W - Add to whitelist (name@version)
q - Quit interactive mode
Your choice [s/i/w/W/q]:๐งถ pnpm Support
Package Age Guard now works with pnpm via hooks that check package ages during installation!
Setup pnpm Hooks
npx package-age-guard --setup-pnpmThis creates a .pnpmfile.cjs in your project root that automatically checks package ages during pnpm install.
pnpm Modes
Configure pnpm behavior in .package-age-guard.json:
{
"minAge": 14,
"pnpmMode": "warn"
}pnpmMode options:
"warn"(default) - Warn about unsafe packages but allow installation"error"- Block installation of packages that are too new"allow"- Disable pnpm hooks entirely
pnpm Usage Examples
# Install with automatic age checking
pnpm install
# With warn mode (default):
# โ ๏ธ axios@1.7.0 is only 2 days old (minimum: 14 days)
# This package is newer than your security policy allows.
# + axios 1.7.0
# With error mode:
# โ Package Age Guard: axios@1.7.0 is only 2 days old
# Package install errorManual pnpm Setup
If you prefer manual setup, create .pnpmfile.cjs:
module.exports = require('package-age-guard/pnpm');Or with custom configuration:
const { hooks } = require('package-age-guard/pnpm');
module.exports = {
readPackage(pkg, context) {
// Custom logic here
return hooks.readPackage(pkg, context);
}
};Programmatic API: Safe Versions
Use safe version suggestions in your code:
import { getSafeVersion, checkPackages, formatResults } from 'package-age-guard';
// Get a specific safe version
const safeVersion = await getSafeVersion('lodash', 30);
console.log(`Safe version: ${safeVersion.version} (${safeVersion.ageDays} days old)`);
// Check with suggestions
const results = await checkPackages({
includeSuggestions: true,
config: { minAge: 14 }
});
// Violations now have .suggestion property
results.violations.forEach(v => {
if (v.suggestion) {
console.log(`${v.name}: ${v.version} โ ${v.suggestion.version}`);
}
});๐ GitHub Action
Package Age Guard is available as an official GitHub Action for easy CI/CD integration!
Quick Start
name: Package Age Check
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Package Ages
uses: MeonValleyWeb/package-age-guard/.github/actions/check-packages@main
with:
min-age: 14
strict: trueGitHub Action Inputs
| Input | Default | Description |
|---|---|---|
min-age |
7 | Minimum package age in days |
production-only |
false | Check production dependencies only |
strict |
false | Exit with error on warnings too |
suggest |
true | Show safe version suggestions |
json-output |
false | Output results as JSON |
config-file |
.package-age-guard.json | Path to config file |
GitHub Action Outputs
| Output | Description |
|---|---|
violations |
Number of packages that are too new |
warnings |
Number of warnings |
passed |
Number of packages that passed |
total |
Total packages checked |
has-violations |
Boolean if violations were found |
results-json |
Full JSON results (if json-output: true) |
Advanced Example with PR Comments
name: Package Security Check
on:
pull_request:
branches: [main]
jobs:
check-packages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Package Ages
uses: MeonValleyWeb/package-age-guard/.github/actions/check-packages@main
id: package-check
with:
min-age: 14
suggest: true
json-output: true
continue-on-error: true
- name: Comment PR with Results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const results = JSON.parse(process.env.RESULTS);
const violations = results.violations || [];
let body = '## ๐ฆ Package Age Guard Results\n\n';
if (violations.length === 0) {
body += 'โ
All packages meet the age requirement!\n';
} else {
body += `โ Found ${violations.length} package(s) newer than 14 days:\n\n`;
body += '| Package | Version | Age | Suggestion |\n';
body += '|---------|---------|-----|------------|\n';
violations.forEach(v => {
const suggestion = v.suggestion ? `\`${v.suggestion.version}\`` : '-';
body += `| ${v.name} | ${v.version} | ${v.age} days | ${suggestion} |\n`;
});
body += '\n๐ก Run `npx package-age-guard --fix` locally to install safe versions.\n';
}
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
env:
RESULTS: ${{ steps.package-check.outputs.results-json }}Integration Examples
As npm preinstall hook
{
"scripts": {
"preinstall": "npx package-age-guard --quiet || true"
}
}Manual GitHub Actions (without the official action)
If you prefer more control, you can use the CLI directly:
name: CI
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Check package ages
run: npx package-age-guard --strict
# Fails if any package is too newAs pre-commit hook
#!/bin/sh
# .git/hooks/pre-commit
npx package-age-guard --quiet || exit 1In package.json scripts
{
"scripts": {
"security:check": "package-age-guard --min=14",
"security:check:ci": "package-age-guard --strict --json"
}
}Whitelisting
Sometimes you need to use a newer package (security patches, critical fixes).
Whitelist by package name (any version)
{
"whitelist": ["lodash", "express"]
}Whitelist specific version
{
"whitelist": ["lodash@4.17.21", "react@18.2.0"]
}CLI override
# Temporarily use a newer version
npm install lodash@latest
# Or with --min=0 (not recommended for CI)
npx package-age-guard --min=0Recommended Minimum Ages
| Use Case | Recommended Min Age | Reason |
|---|---|---|
| Personal projects | 7 days | Balance of security vs convenience |
| Team projects | 14 days | Time for community review |
| CI/CD pipelines | 30 days | Maximum security for automation |
| Financial/crypto | 60+ days | Critical security requirements |
| Production releases | 30 days | Conservative approach |
Exit Codes
| Code | Meaning |
|---|---|
0 |
All packages meet age requirements |
1 |
One or more packages are too new (or warnings in strict mode) |
2 |
Configuration or system error |
FAQ
Q: Will this slow down npm install?
A: Adds ~5-10 seconds for the first install. Results are not cached between runs, but npm registry responses are fast.
Q: What if I need a security patch immediately?
A: You have several options:
- Use
--suggestto see if there's a safe version that still includes the patch - Use
--fixto automatically install safe versions - Use
--interactiveto choose per-package - Add the package to your whitelist temporarily
- Use
--min=0as a last resort (remember to remove it afterward)
Q: Does this work with private registries?
A: Yes, as long as the registry supports npm view commands.
Q: Can I use this in CI/CD?
A: Absolutely! Use --json for programmatic parsing or --strict to fail on warnings too.
Q: What about pre-release versions (beta, alpha, rc)?
A: These are ignored by default since they're often recently published. Use exact versions for pre-releases.
Q: How is age calculated?
A: From the package's time.modified field in npm registry (last publish time of that version).
Comparison with npm audit
| Feature | npm audit |
Package Age Guard |
|---|---|---|
| What it checks | Known vulnerabilities | Package age/supply chain risk |
| When it runs | After install | Before or during install |
| Database | npm security advisories | npm registry timestamps |
| Blocks install? | Configurable | Yes (configurable) |
| Best for | Known CVEs | Zero-day supply chain attacks |
Use both together for maximum protection:
npx package-age-guard && npm install && npm auditContributing
Contributions welcome! Please read our Contributing Guide.
License
MIT ยฉ Meon Valley Web
Pro tip: Star โญ this repo if you find it useful!