Supply Chain Security
Protect your application from compromised dependencies
Supply Chain Security
Supply chain attacks target your dependencies. Malicious code in npm packages can steal secrets, mine crypto, or backdoor your application. This guide covers how to protect against these threats.
The Problem
Your Application
↓
Dependencies (1000+)
↓
Transitive Dependencies (10,000+)
↓
One compromised package = Entire app compromisedReal attacks:
- event-stream (2018): 2M downloads/week, injected Bitcoin stealer
- ua-parser-js (2021): 8M downloads/week, crypto miner injected
- colors/faker (2022): Maintainer sabotaged own packages
- node-ipc (2022): Deleted files on Russian IPs
Risk Assessment
Check Your Dependencies
# Count dependencies
npm ls --all | wc -l
# Check for vulnerabilities
npm audit
# Detailed audit
npm audit --json > audit.jsonDependency Graph
# Visualize dependency tree
npm ls --all
# Check specific package dependencies
npm ls lodash --allProtection Strategies
1. Lock Files
# ✅ Always commit lock files
git add package-lock.json
git commit -m "Add lock file"
# Use npm ci in production (respects lock file exactly)
npm ci
# Don't use npm install in production
# (may install different versions)2. Audit Regularly
# Check for vulnerabilities
npm audit
# Fix automatically (be careful!)
npm audit fix
# Fix only production dependencies
npm audit fix --only=prod
# See what will be fixed
npm audit fix --dry-run3. Snyk
# Install Snyk
npm install -g snyk
# Authenticate
snyk auth
# Test for vulnerabilities
snyk test
# Monitor continuously
snyk monitor
# Test and get actionable advice
snyk test --json | snyk-to-html -o report.html4. GitHub Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
reviewers:
- "your-team"
labels:
- "dependencies"5. Renovate Bot
{
"extends": ["config:base"],
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"matchCurrentVersion": "!/^0/",
"automerge": true
}
],
"vulnerabilityAlerts": {
"enabled": true
}
}6. npm/yarn Security Plugins
# npm audit signatures
npm audit signatures
# Yarn audit
yarn audit
# pnpm audit
pnpm auditPackage Vetting
Before Installing
# Check package info
npm info package-name
# Check downloads
npm info package-name dist.tarball
# Check repository
npm repo package-name
# Check issues
npm bugs package-nameRed Flags
🚩 No repository link
🚩 Very few downloads (< 1000/week)
🚩 No recent updates (> 2 years)
🚩 Suspicious maintainer
🚩 Recently transferred ownership
🚩 Typosquatting name (lodash vs loadash)
🚩 No tests
🚩 Obfuscated code
🚩 Requests unusual permissions
🚩 Large bundle size for simple taskVetting Checklist
// .npmrc - require 2FA for publishes
audit=true
fund=false
package-lock=true
save-exact=trueDependency Pinning
Exact Versions
{
"dependencies": {
"react": "18.2.0", // ✅ Exact version
"lodash": "^4.17.21", // ❌ Allows minor updates
"express": "~4.18.2" // ❌ Allows patch updates
}
}# Install with exact versions
npm install --save-exact package-name
# Configure npm to always use exact versions
npm config set save-exact trueShrinkwrap
# Create shrinkwrap (like package-lock but published to npm)
npm shrinkwrap
# Result: npm-shrinkwrap.json (takes precedence over package-lock.json)Subresource Integrity for CDN
<!-- ✅ Verify integrity of CDN packages -->
<script
src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js"
integrity="sha384-..."
crossorigin="anonymous"
></script>Private Registry
Verdaccio
# Install Verdaccio (private npm registry)
npm install -g verdaccio
# Start registry
verdaccio
# Configure npm to use it
npm set registry http://localhost:4873/
# Publish private packages
npm publish --registry http://localhost:4873/Artifactory / Nexus
# Configure npm to use private registry
npm config set registry https://artifactory.company.com/api/npm/npm-repo/
# Use for specific scope
npm config set @company:registry https://artifactory.company.com/api/npm/npm-repo/Scanning Tools
Socket.dev
# Install
npm install -g socket
# Scan dependencies
socket npx create-react-app my-app
socket install package-nameOSSF Scorecard
# Check project security practices
docker run -e GITHUB_AUTH_TOKEN=token gcr.io/openssf/scorecard:stable \
--repo=github.com/owner/reponpm-audit-ci
# GitHub Actions
name: Security Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm audit --audit-level=moderateAutomated Scanning in CI/CD
GitHub Actions
name: Dependency Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0' # Weekly
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: Check for known vulnerabilities
run: |
npx audit-ci --highPre-commit Hooks
# Install husky
npm install --save-dev husky
# Setup pre-commit hook
npx husky install
npx husky add .git/hooks/pre-commit "npm audit"{
"scripts": {
"prepare": "husky install",
"precommit": "npm audit --audit-level=moderate"
}
}License Compliance
# Check licenses
npx license-checker
# Check for problematic licenses
npx license-checker --onlyAllow 'MIT;ISC;Apache-2.0;BSD-3-Clause'
# Generate report
npx license-checker --json > licenses.jsonBest Practices
1. Minimal Dependencies
# Before adding a dependency, ask:
# - Can I implement this myself?
# - Is there a smaller alternative?
# - Is this actively maintained?
# - Does it have security vulnerabilities?
# Check bundle size impact
npm install --save package-name
npx bundlephobia package-name2. Regular Updates
# Check outdated packages
npm outdated
# Update interactively
npx npm-check -u
# Update all (careful!)
npm update3. Review Changes
# Before updating, review changelogs
npm info package-name
# Check diff
git diff package-lock.json4. Separate Dev Dependencies
{
"dependencies": {
"react": "^18.2.0" // Production only
},
"devDependencies": {
"typescript": "^5.0.0" // Development only
}
}5. Two-Factor Authentication
# Enable 2FA on npm
npm profile enable-2fa auth-and-writes
# Require 2FA for organization
# (npm.com → Organizations → Settings → Require 2FA)Monitoring
Runtime Monitoring
// Detect suspicious behavior at runtime
import crypto from 'crypto';
const originalFetch = global.fetch;
global.fetch = async (...args) => {
const url = args[0]?.toString();
// Detect suspicious domains
if (url && isSuspiciousDomain(url)) {
console.error('⚠️ Suspicious network request:', url);
// Alert security team
}
return originalFetch(...args);
};
function isSuspiciousDomain(url: string): boolean {
const suspiciousPatterns = [
/pastebin\.com/,
/\d+\.\d+\.\d+\.\d+/, // IP addresses
/\.tk$/, // Free TLDs
];
return suspiciousPatterns.some(pattern => pattern.test(url));
}File System Monitoring
// Detect file operations
import fs from 'fs';
const originalWriteFile = fs.writeFile;
fs.writeFile = (path, data, ...args) => {
console.warn('File write detected:', path);
// Block writes to sensitive paths
if (path.includes('/etc/') || path.includes('.ssh')) {
throw new Error('Unauthorized file access');
}
return originalWriteFile(path, data, ...args);
};Incident Response
If Compromised Package Detected
# 1. Immediately remove
npm uninstall compromised-package
# 2. Check if already exploited
git log --all --grep='compromised-package'
# 3. Rotate secrets
# - API keys
# - Database passwords
# - Encryption keys
# - SSH keys
# 4. Audit logs
# - Check for unauthorized access
# - Review network traffic
# - Check file system changes
# 5. Report
# - npm security team: security@npmjs.com
# - GitHub Advisory: github.com/advisoriesSecurity Checklist
✅ Lock files committed (package-lock.json)
✅ npm ci in production (not npm install)
✅ Regular audits (npm audit weekly)
✅ Dependabot/Renovate enabled
✅ 2FA enabled on npm account
✅ Exact versions for critical deps
✅ License compliance checked
✅ CI/CD scanning configured
✅ Minimal dependencies philosophy
✅ Runtime monitoring for suspicious behavior
Common Pitfalls
❌ Not committing lock files: Inconsistent deps
✅ Commit package-lock.json
❌ npm install in production: Wrong versions
✅ npm ci in production
❌ Never updating: Vulnerable to exploits
✅ Regular updates + audits
❌ No 2FA: Account compromise
✅ Enable 2FA on npm
❌ Trusting all packages: Supply chain attack
✅ Vet packages before installing
Supply chain security is critical—vet packages, audit regularly, and minimize dependencies!