In the previous tutorial, you learned how to protect your application with security headers. But even if your code is perfect, a single vulnerable dependency can compromise everything. In this article, you will learn how to scan dependencies for vulnerabilities, prevent supply chain attacks, and keep your software secure.
The Supply Chain Problem
Modern software depends on hundreds of third-party packages. A typical Node.js project has 500-1500 dependencies. A Go project has 50-200. Each dependency is code written by someone else — and any of them could contain a vulnerability.
Real-world supply chain attacks:
- Log4Shell (2021) — a critical vulnerability in Log4j, a Java logging library used by millions of applications. It allowed remote code execution. Almost every Java application was affected.
- SolarWinds (2020) — attackers compromised the build system and injected malware into a software update. 18,000 organizations installed the backdoored update, including US government agencies.
- xz-utils (2024) — a maintainer spent years gaining trust, then injected a backdoor into the compression library used by SSH. Caught by a developer who noticed a 500ms slowdown.
- event-stream (2018) — an attacker gained access to a popular npm package and added code to steal cryptocurrency wallets.
The OWASP Top 10 highlights software supply chain failures because these attacks are growing rapidly.
Level 1: Know Your Dependencies
The first step is knowing what you depend on. Most developers cannot list all their transitive dependencies.
List Dependencies
Go:
# List all dependencies (direct and transitive)
go list -m all
# Show the dependency graph
go mod graph
Python:
# List installed packages
pip freeze > requirements.txt
# Show dependency tree
pip install pipdeptree
pipdeptree
Node.js:
# List all dependencies
npm list --all
# Show only production dependencies
npm list --production
Kotlin/Java (Gradle):
# List all dependencies
./gradlew dependencies
# List only runtime dependencies
./gradlew dependencies --configuration runtimeClasspath
Software Bill of Materials (SBOM)
An SBOM is a complete list of every component in your software — including dependencies, versions, and licenses. Think of it as an ingredients list for software.
Generate an SBOM with Syft:
# Install Syft
brew install syft
# Generate SBOM from a directory
syft dir:. -o spdx-json > sbom.json
# Generate SBOM from a Docker image
syft myapp:latest -o cyclonedx-json > sbom.json
SBOMs are becoming required by regulation. The US Executive Order on Cybersecurity (2021) requires SBOMs for software sold to the government.
Level 2: Scan for Known Vulnerabilities
Vulnerability databases track known security issues in packages. The most important databases are:
- CVE (Common Vulnerabilities and Exposures) — the global standard
- NVD (National Vulnerability Database) — US government database
- GitHub Advisory Database — GitHub’s curated database
- OSV (Open Source Vulnerabilities) — Google’s database for open source
Scanning Tools
Go:
# Built-in vulnerability scanner (since Go 1.18)
govulncheck ./...
# Example output:
# Vulnerability #1: GO-2024-2687
# A malicious HTTP redirect can cause sensitive headers to be
# unexpectedly forwarded.
# Found in: net/http@go1.21.0
# Fixed in: net/http@go1.21.8
Python:
# pip-audit — scans Python dependencies
pip install pip-audit
pip-audit
# Safety — checks requirements.txt
pip install safety
safety check -r requirements.txt
Node.js:
# Built-in audit command
npm audit
# Fix automatically
npm audit fix
# Example output:
# found 3 vulnerabilities (1 low, 1 moderate, 1 high)
Multi-language: Trivy
# Install Trivy
brew install trivy
# Scan a project directory
trivy fs .
# Scan a Docker image
trivy image myapp:latest
# Scan with severity filter
trivy fs --severity HIGH,CRITICAL .
Multi-language: Snyk
# Install Snyk CLI
npm install -g snyk
# Authenticate
snyk auth
# Scan project
snyk test
# Monitor for new vulnerabilities
snyk monitor
Grype (Another Scanner)
# Install Grype
brew install grype
# Scan a directory
grype dir:.
# Scan a Docker image
grype myapp:latest
Level 3: Automate Scanning in CI/CD
Manual scanning is not enough. Automate it so every commit and pull request is scanned.
GitHub Actions with Trivy
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@v0.20.0
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'HIGH,CRITICAL'
exit-code: '1' # Fail the build on high/critical vulnerabilities
GitHub Dependabot
Dependabot automatically creates pull requests to update vulnerable dependencies.
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
Renovate (Alternative to Dependabot)
Renovate is more configurable than Dependabot and supports more ecosystems.
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
},
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true
}
]
}
Level 4: Prevent Supply Chain Attacks
Pin Dependencies
Always pin exact versions. Do not use version ranges.
# BAD — allows any minor/patch update
requests>=2.28.0
lodash^4.17.0
# GOOD — exact version
requests==2.31.0
lodash@4.17.21
Use lockfiles:
- Go:
go.sum(automatically generated) - Python:
requirements.txtwith pinned versions, or usepoetry.lock - Node.js:
package-lock.jsonoryarn.lock - Kotlin/Java: Gradle lockfiles or version catalogs
Verify Package Integrity
Go:
Go modules use go.sum to verify checksums. The Go checksum database (sum.golang.org) provides a global ledger of module hashes.
# Verify all modules
go mod verify
Node.js:
npm uses package-lock.json with integrity hashes.
"lodash": {
"version": "4.17.21",
"integrity": "sha512-v2kDE..."
}
Use Private Registries
For sensitive projects, mirror dependencies in a private registry. This protects against:
- Package deletion (left-pad incident)
- Account takeover of package maintainers
- Typosquatting attacks
Options: Artifactory, Nexus, GitHub Packages, AWS CodeArtifact.
Evaluate Dependencies Before Adding
Before adding a new dependency, check:
| Question | Where to Check |
|---|---|
| Is it actively maintained? | GitHub: last commit date, open issues |
| How many downloads? | npm, PyPI, pkg.go.dev stats |
| How many dependencies does it have? | npm info <pkg> dependencies |
| Are there known vulnerabilities? | snyk test <pkg> or npm audit |
| What license does it use? | license field in package metadata |
| Can I write this myself? | If it is 20 lines of code, do not add a dependency |
Vulnerability Management Process
When a vulnerability is found:
- Assess severity. CVSS score: Critical (9.0-10.0), High (7.0-8.9), Medium (4.0-6.9), Low (0.1-3.9)
- Check exploitability. Is the vulnerable code actually reachable in your application?
- Update or mitigate. Upgrade to a patched version if available. If not, apply a workaround.
- Set deadlines. Critical: 24 hours. High: 7 days. Medium: 30 days. Low: 90 days.
- Document. Track the vulnerability, the fix, and the timeline.
Prevention Checklist
| Defense | Priority | Notes |
|---|---|---|
| Use lockfiles for all package managers | High | Ensures reproducible builds |
Run npm audit / govulncheck / pip-audit in CI | High | Catch vulnerabilities before merge |
| Enable Dependabot or Renovate | High | Automated dependency updates |
| Pin exact dependency versions | High | Prevent unexpected updates |
| Scan Docker images with Trivy | High | Catch vulnerabilities in containers |
| Generate SBOMs for releases | Medium | Required by some regulations |
| Use a private registry for production | Medium | Protect against supply chain attacks |
| Review new dependencies before adding | Medium | Minimize your attack surface |
| Set vulnerability fix deadlines (SLA) | Medium | Critical: 24h, High: 7d, Medium: 30d |
| Verify package integrity (checksums) | Low | Detect tampered packages |
What is Next?
In the next tutorial, you will learn about Security Logging and Monitoring — how to detect attacks in progress, what to log, and how to set up alerts that actually matter.