Security & Performance

Dependency Security

18 min Lesson 11 of 35

Understanding Dependency Security

Modern applications rely on hundreds or thousands of dependencies. Each dependency represents a potential security vulnerability. Managing dependency security is critical to maintaining a secure application.

Supply Chain Attack: An attack that targets vulnerabilities in your dependencies rather than your own code. These attacks can affect millions of applications simultaneously.

Package Vulnerability Scanning

Use automated tools to scan dependencies for known vulnerabilities:

# NPM security audit
npm audit
npm audit --production # Only production dependencies
npm audit fix # Auto-fix vulnerabilities
npm audit fix --force # Force major version updates

# Check specific package
npm audit --package=lodash

# View audit report in JSON
npm audit --json > audit-report.json
Tip: Run npm audit in your CI/CD pipeline and fail builds if critical vulnerabilities are found. Set a threshold that works for your project.

Using Snyk for Dependency Security

Snyk provides comprehensive vulnerability scanning and remediation advice:

# Install Snyk CLI
npm install -g snyk

# Authenticate
snyk auth

# Test project for vulnerabilities
snyk test

# Monitor project continuously
snyk monitor

# Test and fix vulnerabilities
snyk test --severity-threshold=high
snyk fix

# Test Docker images
snyk container test node:18-alpine

# Test infrastructure as code
snyk iac test ./terraform/
Snyk Features: Snyk scans for vulnerabilities in dependencies, container images, infrastructure as code, and provides automated pull requests with fixes.

GitHub Dependabot Configuration

Dependabot automatically creates pull requests to update vulnerable dependencies:

# .github/dependabot.yml
version: 2
updates:
# Enable version updates for npm
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
open-pull-requests-limit: 10
reviewers:
- "security-team"
labels:
- "dependencies"
- "security"
# Group updates together
groups:
development-dependencies:
dependency-type: "development"
production-dependencies:
dependency-type: "production"

# Enable security updates for Docker
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"

Lock File Security

Lock files ensure reproducible builds but can hide vulnerabilities:

# package-lock.json security best practices

# 1. Always commit lock files
git add package-lock.json

# 2. Verify lock file integrity
npm ci # Uses exact versions from lock file

# 3. Audit lock file for vulnerabilities
npm audit

# 4. Update lock file when patching
npm update --package-lock-only

# 5. Check for compromised packages
npm audit signatures
Warning: Using npm install can update dependencies beyond what's in your lock file. In CI/CD, always use npm ci to ensure exact versions are installed.

Preventing Supply Chain Attacks

Supply chain attacks exploit trust in third-party packages:

# 1. Verify package integrity
npm config set package-lock true
npm config set audit true

# 2. Use package signatures (npm 9+)
npm install --signature-check

# 3. Check package reputation before installing
# - Check npm downloads
# - Review GitHub stars/issues
# - Check maintainer reputation
# - Review recent commits

# 4. Pin exact versions in package.json
{
"dependencies": {
"express": "4.18.2", // Good: exact version
"lodash": "^4.17.21", // Bad: allows minor updates
"axios": "~1.4.0" // Bad: allows patch updates
}
}

# 5. Use private registry for sensitive projects
npm config set registry https://registry.company.com

Dependency Review Process

Implement a manual review process for new dependencies:

Security Review Checklist:
  • Popularity: Is it widely used? (npm weekly downloads)
  • Maintenance: Recently updated? Active maintainer?
  • License: Compatible with your project?
  • Dependencies: How many transitive dependencies?
  • Security History: Any past vulnerabilities?
  • Code Quality: TypeScript? Tests? Documentation?
  • Bundle Size: Impact on application size?
  • Alternatives: Could you implement it yourself?

Automated Dependency Updates

# Renovate Bot configuration (renovate.json)
{
"extends": ["config:base"],
"schedule": ["before 9am on Monday"],
"labels": ["dependencies"],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"],
"assignees": ["@security-team"]
},
"packageRules": [
{
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["breaking-change"]
},
{
"matchUpdateTypes": ["minor", "patch"],
"matchCurrentVersion": "<1.0.0",
"automerge": false
},
{
"matchDepTypes": ["devDependencies"],
"automerge": true,
"automergeType": "pr"
}
]
}
Best Practice: Automate patch and minor updates for development dependencies, but require manual review for production dependencies and major version updates.

Runtime Dependency Protection

// Monitor dependencies at runtime
const depcheck = require('depcheck');

const options = {
ignoreBinPackage: false,
skipMissing: false,
ignorePatterns: ['dist', 'build']
};

depcheck('/path/to/project', options, (unused) => {
console.log('Unused dependencies:', unused.dependencies);
console.log('Missing dependencies:', unused.missing);
});

// Subresource Integrity (SRI) for CDN resources
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
crossorigin="anonymous"
></script>
Exercise: Audit your project dependencies:
  1. Run npm audit and review all vulnerabilities
  2. Install Snyk and run snyk test
  3. Configure Dependabot for your repository
  4. Create a dependency review checklist document
  5. Set up automated dependency update PRs