
Npm Security Best Practices
- 894 installs
- 10 repo stars
- Updated August 4, 2026
- aradotso/security-skills
npm-security-best-practices is a Claude Code skill that hardens npm, pnpm, and Bun installations against supply-chain attacks for developers who add dependencies and need secure package-manager configuration before insta
About
npm-security-best-practices is a Claude Code skill from aradotso/security-skills providing expert guidance on securing npm package installations, preventing supply-chain attacks, and hardening package-manager configurations across npm, pnpm, and Bun. Trigger phrases cover securing dependencies, blocking malicious packages, disabling postinstall scripts, preventing dependency confusion, and setting secure install defaults. Developers reach for this skill before adding new packages, during security reviews, or when CI must enforce hardened registry and script policies. The skill focuses on configuration and process guardrails—registry settings, install script controls, and dependency trust boundaries—rather than rewriting application business logic. It helps teams treat package managers as part of the attack surface, not passive utilities.
- Prevents dependency confusion, malicious postinstall scripts, and supply-chain worms such as Shai-Hulud, Nx, and event-s
- Generates secure-by-default .npmrc, .yarnrc, and pnpm config with 12 hardening flags
- Audits package.json and lockfiles for risky lifecycle scripts and version ranges
- Recommends exact versions, integrity hashes, and allowed registries
- Works for npm, pnpm, Yarn, and Bun with one command
Npm Security Best Practices by the numbers
- 894 all-time installs (skills.sh)
- +104 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #416 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aradotso/security-skills --skill npm-security-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 894 |
|---|---|
| repo stars | ★ 10 |
| Last updated | August 4, 2026 |
| Repository | aradotso/security-skills ↗ |
How do you secure npm dependencies against supply-chain attacks?
Lock down npm, pnpm and Bun against supply-chain attacks before installing any new dependencies.
Who is it for?
JavaScript and TypeScript developers adopting new npm, pnpm, or Bun dependencies who need supply-chain hardening guidance before installs hit CI or production.
Skip if: Skip npm-security-best-practices for non-JavaScript ecosystems or when security scanning and registry policy are already enforced by a dedicated platform team tool.
When should I use this skill?
The developer asks how to secure npm dependencies, disable postinstall scripts, block malicious packages, or harden package-manager configuration against supply-chain attacks.
What you get
Hardened package-manager configuration, disabled risky install scripts, and documented guardrails against dependency confusion and malicious npm packages.
- Hardened package-manager config
- Postinstall script policy
- Supply-chain guardrail checklist
Files
npm Security Best Practices
Skill by ara.so — Security Skills collection.
This skill provides expert guidance on securing npm package installations, preventing supply chain attacks, and implementing security best practices for Node.js development. Based on the comprehensive npm-security-best-practices repository by Lirantal.
Overview
The npm ecosystem is a frequent target for supply chain attacks including:
- Shai-Hulud attacks - Worm-like propagation through compromised packages
- Nx incident - Malicious code in postinstall scripts
- event-stream attack - Long-running exfiltration via lifecycle scripts
- Dependency confusion - Attackers publishing malicious packages with internal names
This skill covers configuration, tooling, and practices to mitigate these risks across npm, pnpm, and Bun.
Secure-by-Default Configuration
npm (.npmrc)
Create or update .npmrc in your project root or global config (~/.npmrc):
# Disable all lifecycle scripts (postinstall, preinstall, etc.)
ignore-scripts=true
# Block git-based dependencies (git+ssh://, git+https://, etc.)
allow-git=none
# Only install packages that have been published for at least 30 days
min-release-age=30Apply globally:
npm config set ignore-scripts true
npm config set allow-git none
npm config set min-release-age 30pnpm (pnpm-workspace.yaml)
Create pnpm-workspace.yaml in your project root:
# Block packages newer than 30 days (43200 minutes)
minimumReleaseAge: 43200
# Reject versions with regressed trust signals (pnpm 10.21+)
trustPolicy: no-downgrade
# Allowlist for packages that need build scripts
allowBuilds:
esbuild: true
rolldown: true
nx@21.6.4 || 21.6.5: true
# Fail install if unlisted scripts try to run
strictDepBuilds: true
# Block git URLs in dependencies
blockExoticSubdeps: true
# Optional: ignore trust policy for legacy packages
trustPolicyIgnoreAfter: 43200
# Optional: exempt specific packages from trust policy
trustPolicyExclude:
- 'chokidar@4.0.3'Bun (package.json)
Bun disables postinstall scripts by default. To allow specific packages:
{
"trustedDependencies": [
"esbuild",
"sharp",
"fsevents"
]
}Installation Commands
Secure npm install
# Install with security flags
npm install --ignore-scripts --allow-git=none
# Use npm ci for reproducible installs (CI/CD)
npm ci --ignore-scripts
# Install specific package securely
npm install lodash --ignore-scripts --allow-git=noneSecure pnpm install
# Install with workspace config enforced
pnpm install
# Review blocked packages
pnpm install --loglevel=verbose
# Bypass trust policy for specific install (use sparingly)
pnpm install --ignore-trust-policySelective script execution
Use @lavamoat/allow-scripts for granular control:
# Install the tool
npm install -g @lavamoat/allow-scripts
# Create allowlist
npx allow-scripts setup
# Edit package.json to add allowlistExample package.json:
{
"scripts": {
"prepare": "allow-scripts"
},
"lavamoat": {
"allowScripts": {
"esbuild": true,
"core-js": false,
"nx>@nx/nx-linux-x64-gnu": true
}
}
}Hardening npx Execution
# Execute without installing package
npx --no-install create-react-app my-app
# Use specific version to avoid typosquatting
npx create-react-app@5.0.1 my-app
# Verify package before running
npm view create-react-app
npx create-react-app my-app
# Use with security wrappers (see below)Security Tooling Integration
npq - Package quality and security checks
# Install globally
npm install -g npq
# Use instead of npm install
npq install lodash
# Check package before installing
npq check lodashSocket Firewall (sfw)
# Install globally
npm install -g @socketsecurity/cli
# Protect npm install
npx @socketsecurity/cli npm install
# Audit project dependencies
npx @socketsecurity/cli audit
# Check specific package
npx @socketsecurity/cli info lodashSnyk - Vulnerability scanning
# Install CLI
npm install -g snyk
# Authenticate
snyk auth
# Test for vulnerabilities
snyk test
# Monitor project
snyk monitor
# Check for supply chain issues
snyk code testAutomated Dependency Updates with Cooldown
Renovate Bot (renovate.json)
{
"extends": ["config:base"],
"minimumReleaseAge": "30 days",
"stabilityDays": 30,
"prCreation": "not-pending",
"packageRules": [
{
"matchUpdateTypes": ["major"],
"minimumReleaseAge": "60 days"
}
]
}Dependabot (.github/dependabot.yml)
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
# Dependabot doesn't support minimumReleaseAge natively
# Use branch protection rules and manual delay
open-pull-requests-limit: 10
labels:
- "dependencies"
- "security"Use GitHub Actions to enforce cooldown:
name: Dependency Cooldown Check
on:
pull_request:
paths:
- 'package.json'
- 'package-lock.json'
jobs:
check-release-age:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check package age
run: |
# Custom script to verify package age
node scripts/check-package-age.jsLockfile Security
Prevent lockfile injection
# Review lockfile changes in PRs
git diff package-lock.json
# Verify integrity
npm audit
# Regenerate if suspicious
rm package-lock.json
npm install --ignore-scripts.gitattributes protection
# Prevent merge conflicts from hiding malicious changes
package-lock.json merge=binary
pnpm-lock.yaml merge=binaryPackage Health Assessment
Snyk Advisor lookup
# Check package health
curl https://snyk.io/advisor/npm-package/lodash | jq
# CLI check
npx snyk-advisor lodashManual verification checklist
// check-package-health.js
const fetch = require('node-fetch');
async function checkPackage(packageName) {
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
const data = await response.json();
const latestVersion = data['dist-tags'].latest;
const versionInfo = data.versions[latestVersion];
console.log(`Package: ${packageName}@${latestVersion}`);
console.log(`Published: ${versionInfo.time || 'N/A'}`);
console.log(`Maintainers: ${data.maintainers?.length || 0}`);
console.log(`License: ${versionInfo.license || 'NONE'}`);
console.log(`Has scripts: ${!!versionInfo.scripts}`);
console.log(`Dependencies: ${Object.keys(versionInfo.dependencies || {}).length}`);
// Check provenance (npm 9.5+)
if (versionInfo.dist?.attestations) {
console.log('✓ Has provenance attestation');
} else {
console.log('⚠ No provenance attestation');
}
}
checkPackage(process.argv[2]);Run:
node check-package-health.js lodashPreventing Dependency Confusion
.npmrc scoped registries
# Use private registry for org packages
@mycompany:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
# Public packages from npm
registry=https://registry.npmjs.org/package.json name scoping
{
"name": "@mycompany/internal-lib",
"version": "1.0.0",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}Dev Container Security
.devcontainer/devcontainer.json
{
"name": "Secure Node.js Dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"postCreateCommand": "npm config set ignore-scripts true && npm config set allow-git none",
"remoteEnv": {
"NPM_CONFIG_IGNORE_SCRIPTS": "true",
"NPM_CONFIG_ALLOW_GIT": "none"
},
"mounts": [
"source=${localEnv:HOME}/.npmrc,target=/home/node/.npmrc,type=bind,consistency=cached"
]
}Environment Variable Security
Use .env.vault instead of plaintext .env
# Install dotenv-vault
npm install dotenv-vault
# Encrypt secrets
npx dotenv-vault local build
# Generate .env.vault (encrypted)
npx dotenv-vault push
# .gitignore update
echo ".env" >> .gitignore
echo ".env.*.vault" >> .gitignoreAccess encrypted secrets
// app.js
require('dotenv-vault-core').config();
const apiKey = process.env.API_KEY; // Decrypted at runtimeMaintainer Best Practices
Enable 2FA on npm account
# Enable 2FA
npm profile enable-2fa auth-and-writes
# Verify status
npm profile getPublish with provenance (npm 9.5+)
# Publish with provenance attestation
npm publish --provenance
# Verify in package.json before publishing
npm pack --dry-runGitHub Actions OIDC publishing
# .github/workflows/publish.yml
name: Publish Package
on:
release:
types: [created]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm ci --ignore-scripts
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Troubleshooting
Scripts are blocked but package needs them
Problem: A legitimate package requires postinstall scripts.
Solution: Use allowlist approach with @lavamoat/allow-scripts or pnpm allowBuilds:
# pnpm approach
# Add to pnpm-workspace.yaml
allowBuilds:
problematic-package: true
# npm/yarn approach with lavamoat
npm install @lavamoat/allow-scripts
npx allow-scripts setup
# Edit package.json lavamoat.allowScripts sectionGit dependency is required
Problem: Internal package only available via git URL.
Solution: Use private npm registry instead:
# Publish to GitHub Packages
echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc
npm publish --registry=https://npm.pkg.github.com
# Or use Verdaccio for self-hosted registry
npm install -g verdaccio
verdaccioCooldown period blocks urgent security fix
Problem: Security patch released but blocked by min-release-age.
Solution: Temporarily override for specific package:
# npm - install specific version without min-release-age
npm install package@1.2.3 --no-min-release-age
# pnpm - add to trustPolicyExclude
# In pnpm-workspace.yaml:
trustPolicyExclude:
- 'package@1.2.3'Trust policy blocks legitimate package
Problem: pnpm trust policy rejects package downgrade.
Solution: Investigate first, then exempt if safe:
# Check what changed
npm view package@version dist.integrity
npm view package@old-version dist.integrity
# If legitimate, exempt in pnpm-workspace.yaml
trustPolicyExclude:
- 'package@version'False positive from security scanner
Problem: Snyk/Socket reports issue in vetted package.
Solution: Create exceptions with justification:
# .snyk
ignore:
SNYK-JS-LODASH-12345:
- lodash:
reason: 'Prototype pollution not exploitable in our use case'
expires: '2024-12-31'CI/CD Integration
GitHub Actions security workflow
name: Security Audit
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: Install with security flags
run: npm ci --ignore-scripts
- name: Audit dependencies
run: npm audit --audit-level=moderate
- name: Check with Socket
run: npx @socketsecurity/cli audit
env:
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_API_KEY }}
- name: Snyk security scan
run: npx snyk test --severity-threshold=high
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}Additional Resources
Related skills
How it compares
Use npm-security-best-practices for install-time policy and manager configuration; pair with vulnerability scanners for CVE detection on already-locked dependencies.
FAQ
Which package managers does npm-security-best-practices cover?
npm-security-best-practices covers npm, pnpm, and Bun installations. The skill hardens registry and install settings, helps disable risky postinstall scripts, and addresses supply-chain and dependency confusion risks before new packages enter the project.
When should developers invoke npm-security-best-practices?
npm-security-best-practices triggers on questions about securing npm dependencies, blocking malicious packages, configuring package manager security, or disabling postinstall scripts. Use it during security review before adding unfamiliar packages.