Supply Chain Security
Secure your software supply chain by auditing dependencies, pinning versions, verifying integrity, and monitoring for vulnerabilities.
You are an expert in securing the software supply chain — managing third-party dependencies, detecting malicious packages, enforcing integrity checks, and maintaining a secure build pipeline.
## Key Points
1. **Lockfiles**: Pin exact versions of every dependency (direct and transitive).
2. **Integrity hashes**: Verify package contents match expected checksums.
3. **Vulnerability scanning**: Automated checks for known CVEs.
4. **License compliance**: Ensure all dependencies use acceptable licenses.
5. **Supply chain attestation**: Verify provenance — who built the package and how.
6. **Minimal dependencies**: Fewer dependencies mean a smaller attack surface.
- name: Install dependencies
- name: Run install scripts selectively
- name: Audit Python dependencies
- package-ecosystem: npm
- package-ecosystem: pip
- package-ecosystem: docker
## Quick Example
```yaml
# GitHub Actions
- name: Audit Python dependencies
run: |
pip install pip-audit
pip-audit --requirement requirements.txt --strict --desc
```
```ini
# .npmrc — prevent dependency confusion
@mycompany:registry=https://npm.mycompany.com/
# Public packages still come from the public registry
registry=https://registry.npmjs.org/
```skilldb get security-practices-skills/Supply Chain SecurityFull skill: 316 linesDependency and Supply Chain Security — Application Security
You are an expert in securing the software supply chain — managing third-party dependencies, detecting malicious packages, enforcing integrity checks, and maintaining a secure build pipeline.
Core Philosophy
Supply chain security starts with the recognition that every dependency is code you did not write, did not review, and do not fully control — yet it runs with the same privileges as your own application. The moment you add a package, you are extending trust to its author, every transitive dependency author, and the infrastructure that builds and distributes it. This trust must be explicit, bounded, and continuously verified rather than silently assumed.
The most effective supply chain defense is a small attack surface. Every dependency that does not exist cannot be compromised. Before reaching for a package, teams should ask whether the functionality justifies the risk: a two-line utility function copied into the codebase carries zero ongoing supply chain risk, while an npm package with the same functionality introduces a maintainer account, a build pipeline, and a transitive dependency tree that could be compromised at any point. Minimalism is the strongest form of supply chain security.
Verification must be continuous, not a one-time gate. A dependency that was safe when it was added can be compromised through a maintainer account takeover, a malicious patch release, or a newly disclosed CVE in a transitive dependency months later. Mature supply chain practices treat dependency auditing as an ongoing operational responsibility — automated scanning on every PR, scheduled vulnerability checks, lockfile review as a first-class part of code review, and alerts when a dependency's risk profile changes.
Anti-Patterns
-
Adding packages without evaluating their dependency tree: Installing a package because it solves an immediate problem without inspecting its transitive dependencies, maintainer activity, or download trends imports unknown risk. A single compromised transitive dependency can affect hundreds of downstream projects.
-
Running
npm installinstead ofnpm ciin CI/CD:npm installcan modify the lockfile and resolve different versions than what was tested locally.npm ciinstalls exactly what the lockfile specifies, ensuring reproducible builds and preventing silent version drift. -
Auto-merging all dependency update PRs without review: Automated tools like Dependabot and Renovate are essential for keeping dependencies current, but rubber-stamping every update — especially major version bumps — skips the human judgment needed to catch breaking changes or suspicious modifications.
-
Ignoring
postinstallscripts in untrusted packages: Install scripts run arbitrary code with the permissions of the installing user. A maliciouspostinstallscript can exfiltrate environment variables, install backdoors, or modify other packages. Use--ignore-scriptsby default and audit scripts before allowing them. -
Using mutable Docker tags like
latestornode:20without pinning by digest: Tags can be overwritten at any time, meaning adocker pulltoday may return a different image than the same pull yesterday. Pinning by digest guarantees you deploy the exact image you tested.
Overview
Modern applications depend on hundreds or thousands of open-source packages. Each dependency is a potential entry point for malicious code, whether through compromised maintainer accounts, typosquatting, or vulnerable transitive dependencies. Supply chain security ensures that every dependency is intentional, verified, up-to-date, and monitored.
Core Concepts
Attack Vectors
| Vector | Description |
|---|---|
| Typosquatting | Malicious package with a similar name (e.g., colors vs c0lors) |
| Dependency confusion | Public package with the same name as a private/internal package |
| Compromised maintainer | Attacker gains access to a legitimate maintainer's account |
| Malicious install scripts | postinstall scripts that run arbitrary code during npm install |
| Vulnerable dependency | Known CVE in a transitive dependency |
| Abandoned package | Unmaintained package acquired by a malicious actor |
Defense Layers
- Lockfiles: Pin exact versions of every dependency (direct and transitive).
- Integrity hashes: Verify package contents match expected checksums.
- Vulnerability scanning: Automated checks for known CVEs.
- License compliance: Ensure all dependencies use acceptable licenses.
- Supply chain attestation: Verify provenance — who built the package and how.
- Minimal dependencies: Fewer dependencies mean a smaller attack surface.
SBOM (Software Bill of Materials)
An SBOM is a machine-readable inventory of all components in your software, including dependencies and their versions. Standards include SPDX and CycloneDX.
Implementation Patterns
Lockfile Enforcement
// package.json — enforce exact versions with save-exact
{
"name": "my-app",
"config": {
"save-exact": true
}
}
# .npmrc — enforce lockfile consistency
save-exact=true
engine-strict=true
# CI should fail if lockfile is out of date
# In CI:
npm ci # not npm install — ci uses lockfile exactly
# GitHub Actions — verify lockfile integrity
- name: Install dependencies
run: npm ci --ignore-scripts # skip install scripts for safety
- name: Run install scripts selectively
run: npx --yes allow-scripts
npm Audit in CI
# GitHub Actions workflow
name: Security Audit
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 8 * * 1' # Weekly Monday 8am
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Audit for critical/high vulnerabilities
run: npm audit --audit-level=high
- name: Check for outdated packages
run: npm outdated || true # informational, don't fail
Python — pip-audit and Safety
# Install pip-audit
pip install pip-audit
# Scan for known vulnerabilities
pip-audit --requirement requirements.txt --strict
# Or use safety
pip install safety
safety check --full-report
# GitHub Actions
- name: Audit Python dependencies
run: |
pip install pip-audit
pip-audit --requirement requirements.txt --strict --desc
Dependabot Configuration
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
reviewers:
- security-team
labels:
- dependencies
- security
# Group minor and patch updates
groups:
minor-and-patch:
update-types:
- minor
- patch
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
- package-ecosystem: docker
directory: "/"
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
Renovate Configuration
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"security:openssf-scorecard",
":pinAllExceptPeerDependencies"
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
},
"packageRules": [
{
"matchUpdateTypes": ["major"],
"labels": ["breaking-change"],
"automerge": false
},
{
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "pr",
"requiredStatusChecks": ["ci"]
}
]
}
Docker Image Scanning
# Pin base images by digest, not just tag
FROM node:20-alpine@sha256:abc123def456...
# Use multi-stage builds to minimize final image
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --ignore-scripts
COPY . .
RUN npm run build
FROM node:20-alpine@sha256:abc123def456...
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]
# Scan Docker images in CI
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:latest'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
SBOM Generation
# Generate CycloneDX SBOM for Node.js
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
# Generate SPDX SBOM
npx spdx-sbom-generator
# Python
pip install cyclonedx-bom
cyclonedx-py requirements --format json --output sbom.json
Private Registry and Scoped Packages
# .npmrc — prevent dependency confusion
@mycompany:registry=https://npm.mycompany.com/
# Public packages still come from the public registry
registry=https://registry.npmjs.org/
# pip.conf — use a private index for internal packages
[global]
index-url = https://pypi.org/simple/
extra-index-url = https://pypi.mycompany.com/simple/
Socket.dev / OpenSSF Scorecard
# GitHub Actions — OpenSSF Scorecard
- name: OSSF Scorecard
uses: ossf/scorecard-action@v2
with:
results_file: scorecard-results.json
results_format: json
publish_results: true
# Socket.dev — detect supply chain risks in PRs
# Install the Socket GitHub App for automated PR analysis
# https://socket.dev
Best Practices
- Always use lockfiles:
package-lock.json,yarn.lock,pnpm-lock.yaml,Pipfile.lock, orpoetry.lock. Commit them to source control. - Run
npm ci(notnpm install) in CI: This ensures the lockfile is respected exactly. - Pin dependencies to exact versions: Avoid
^and~ranges in production applications. Lockfiles help, but pinning makes intent explicit. - Audit continuously, not just once: Run vulnerability scans in CI on every PR and on a weekly schedule.
- Minimize your dependency tree: Before adding a package, evaluate whether you truly need it. Fewer dependencies mean fewer attack vectors.
- Review dependency changes in PRs: Lockfile diffs should be reviewed, not rubber-stamped. Unexpected dependency additions are a red flag.
- Use
--ignore-scriptsfor untrusted packages: Install scripts can run arbitrary code. Audit scripts before allowing them. - Pin Docker base images by digest: Tags are mutable. Digests guarantee you get the exact image you tested.
- Generate and publish SBOMs: SBOMs enable downstream users to track vulnerabilities in your software.
- Use a private registry for internal packages: This prevents dependency confusion attacks where a public package shadows your internal one.
Common Pitfalls
- Ignoring transitive dependencies: Your direct dependencies are fine, but their dependencies may be vulnerable. Audit the full tree.
- Auto-merging major version bumps: Major versions can include breaking changes and may introduce new dependencies. Review them manually.
- Not monitoring after deployment: New CVEs are disclosed daily. A clean audit today does not mean clean tomorrow. Run scheduled scans.
- Trusting download counts: Popular packages can be compromised. The
event-streamincident affected a package with millions of weekly downloads. - Using
npm installin CI: It can modify the lockfile and install different versions than tested. Always usenpm ci. - Failing to scope private packages: Without a configured scope, npm may fetch a public package with the same name as your private one.
- Not verifying package provenance: npm now supports provenance attestations. Check that packages are built from their claimed source repository.
Install this skill directly: skilldb add security-practices-skills
Related Skills
Content Security Policy
Configure Content-Security-Policy headers to mitigate XSS, data injection, and clickjacking attacks.
CORS Security
Configure CORS headers correctly to control cross-origin resource access while preventing overly permissive policies.
CSRF Protection
Protect web applications against cross-site request forgery (CSRF) using tokens, SameSite cookies, and origin validation.
Input Validation
Validate and sanitize all user input at application boundaries using schemas, type coercion, and allowlists.
Secrets Management
Securely store, access, rotate, and audit application secrets and credentials using vaults, environment variables, and CI/CD integrations.
SQL Injection
Prevent SQL injection attacks using parameterized queries, ORM best practices, and input validation layers.