Managing Dependency Security
Third-party dependencies are a major attack vector. Supply chain attacks, vulnerable packages, and malicious code can compromise your entire application.
Vulnerability Scanning
npm audit
# Check for vulnerabilities
npm audit
# Get JSON output for CI/CD
npm audit --json
# Fix automatically where possible
npm audit fix
# Force fix (may include breaking changes)
npm audit fix --force
# Only check production dependencies
npm audit --production
Snyk
# Install Snyk
npm install -g snyk
# Authenticate
snyk auth
# Test for vulnerabilities
snyk test
# Monitor project continuously
snyk monitor
# Fix vulnerabilities
snyk fix
Lock Files
# Always commit lock files
# package-lock.json (npm)
# yarn.lock (Yarn)
# pnpm-lock.yaml (pnpm)
# Use exact versions in CI
npm ci # Instead of npm install
# Verify integrity
npm ci --ignore-scripts
Automated Updates with Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
# Group minor and patch updates
groups:
minor-and-patch:
update-types:
- "minor"
- "patch"
# Ignore specific packages
ignore:
- dependency-name: "aws-sdk"
update-types: ["version-update:semver-major"]
# Security updates only
# schedule:
# interval: "daily"
# open-pull-requests-limit: 20
Renovate Bot Configuration
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":semanticCommits",
"schedule:weekly"
],
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"groupName": "minor and patch updates",
"automerge": true
},
{
"matchPackagePatterns": ["eslint", "prettier"],
"groupName": "linting tools"
},
{
"matchDepTypes": ["devDependencies"],
"automerge": true
}
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
}
}
Pre-install Script Checking
// package.json
{
"scripts": {
"preinstall": "npx npm-run-all check:*",
"check:audit": "npm audit --audit-level=high",
"check:licenses": "license-checker --production --onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC'"
}
}
Using npm-shrinkwrap for Production
# Create shrinkwrap file (more strict than package-lock.json)
npm shrinkwrap
# This creates npm-shrinkwrap.json which:
# - Takes precedence over package-lock.json
# - Is published with the package
# - Ensures exact dependency tree in production
Subresource Integrity (SRI) for CDN
<!-- Always use SRI when loading from CDN -->
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>
<link
rel="stylesheet"
href="https://cdn.example.com/styles.css"
integrity="sha384-..."
crossorigin="anonymous"
>
# Generate SRI hash
echo -n "console.log('hello');" | openssl dgst -sha384 -binary | openssl base64 -A
# Or use srihash.org
Private Registry
# .npmrc for private registry
registry=https://registry.npmjs.org/
@mycompany:registry=https://npm.mycompany.com/
# Verdaccio for self-hosted registry
npm install -g verdaccio
verdaccio
# Publish to private registry
npm publish --registry https://npm.mycompany.com/
GitHub Actions Security Workflow
# .github/workflows/security.yml
name: Security Check
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * *' # Daily
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- 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 licenses
run: |
npx license-checker --production --onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC'
Best Practices
- Always commit lock files
- Use
npm ciin CI/CD - Run
npm auditregularly - Set up automated dependency updates
- Use SRI for CDN resources
- Review dependency changes in PRs
- Minimize dependencies (prefer standard library)
- Check package health before installing
- Use scoped packages for internal code
- Consider using a private registry