# Supply Chain Security

> Reviews JavaScript project supply chain security including npm provenance, install scripts, CI/CD integrity, typosquatting, and dependency pinning. Use for supply chain audits, SBOM requests, or when the user asks about npm security, package integrity, or software supply chain risks.

- Skill: `leo4135/supply-chain-security` (Agent Skill)
- Install (CLI): `npx skillmds@latest add leo4135/supply-chain-security`
- Raw SKILL.md: https://api.skillmd.com/api/skills/leo4135/supply-chain-security/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: leo4135 (https://skillmd.com/u/leo4135)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/leo4135/supply-chain-security

---


# Supply Chain Security

## Audit Workflow

```
Supply Chain Audit:
- [ ] Lockfile & integrity verification
- [ ] Install script review
- [ ] CI/CD pipeline security
- [ ] Package provenance & publishing
- [ ] Typosquatting & dependency confusion
- [ ] Secrets in CI/CD and artifacts
- [ ] Third-party script integrity (SRI)
```

## Lockfile & Install Integrity

```bash
# Lockfile present and used
ls package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

# CI should use frozen installs
rg -n "npm (ci|install)|yarn install|pnpm install" .github/ .gitlab-ci.yml 2>/dev/null

# Verify no scripts run unchecked in CI
rg -n "ignore-scripts" .github/ 2>/dev/null
```

**Rules:**
- Never `npm install` in CI — use `npm ci`
- Pin Node.js version (`.nvmrc`, `engines` field, CI matrix)
- Enable `npm audit` in CI pipeline
- Consider `--ignore-scripts` until packages are vetted

## Install Script Risks

High-risk lifecycle scripts: `preinstall`, `install`, `postinstall`, `prepare`

```bash
# Find packages with install scripts in your tree
node -e "
const {execSync}=require('child_process');
try {
  const out=execSync('npm ls --all --parseable 2>/dev/null',{encoding:'utf8'});
  // Manual review of node_modules/*/package.json scripts recommended
} catch(e) {}
"

rg -l "postinstall|preinstall" node_modules/*/package.json 2>/dev/null | head -20
```

| Risk Level | Indicator |
|------------|-----------|
| Critical | Install script makes network requests to unknown domains |
| High | Install script accesses `process.env` for exfiltration |
| Medium | Native compilation (node-gyp) — expected for some packages |
| Low | `prepare` running build — common for TypeScript packages |

## Typosquatting & Dependency Confusion

Check for:
- Package names similar to popular packages (e.g., `lodash` vs `lodahs`)
- Internal package names published publicly
- Scoped vs unscoped confusion (`@company/pkg` vs `company-pkg`)

```bash
# Review direct dependency names for typos
node -e "console.log(Object.keys({...require('./package.json').dependencies}))"

# Private registry config
rg -n "registry|@.*:registry" .npmrc .yarnrc.yml 2>/dev/null
```

**Mitigations:**
- Use scoped private packages (`@yourorg/package`)
- Configure `.npmrc` with scoped registry for internal packages
- Enable npm provenance and trusted publishing
- Review new dependencies in PRs

## CI/CD Pipeline Security

```bash
rg -n "secrets\.|GITHUB_TOKEN|NPM_TOKEN|password" .github/ .gitlab-ci.yml 2>/dev/null
rg -n "pull_request_target|workflow_run" .github/workflows/ 2>/dev/null
```

| Check | Requirement |
|-------|-------------|
| Secrets scoped | Minimal permissions per workflow |
| PR workflows | No secret access on untrusted forks |
| `pull_request_target` | Never checkout untrusted code with secrets |
| Action pinning | Pin to SHA, not `@v1` tags |
| Artifact signing | Sign releases, verify in deployment |
| OIDC | Use OIDC for cloud deploys (no long-lived keys) |

### GitHub Actions Hardening

```yaml
permissions:
  contents: read

# Pin actions to commit SHA
- uses: actions/checkout@<sha>  # not @v4
```

## npm Provenance & Publishing

For projects that publish packages:
- Enable [npm provenance](https://docs.npmjs.com/generating-provenance-statements)
- Use 2FA on npm account (publish + authorize)
- Use trusted publishers (GitHub OIDC)
- Never share npm tokens — use CI OIDC

## SBOM (Software Bill of Materials)

```bash
# Generate SBOM
npx --yes @cyclonedx/cyclonedx-npm --output-file sbom.json 2>/dev/null
# or
npx --yes @anchore/syft packages dir:. -o cyclonedx-json 2>/dev/null
```

Include SBOM in releases for enterprise consumers.

## Third-Party Scripts (Frontend)

```bash
rg -n "<script.*src=" --glob "*.{html,jsx,tsx,vue,svelte}"
rg -n "integrity=" --glob "*.{html,jsx,tsx}"
```

**Rules:**
- Subresource Integrity (SRI) on all CDN scripts
- Allowlist CDN domains in CSP `script-src`
- Self-host critical libraries when possible
- Monitor CDN compromises

## Environment & Artifact Leaks

```bash
# Secrets in build output
rg -n "API_KEY|SECRET|PASSWORD|PRIVATE" dist/ .next/ build/ 2>/dev/null

# .env in Docker images
rg -n "COPY.*\.env|ADD.*\.env" Dockerfile* 2>/dev/null
```

## Report Template

```markdown
## Supply Chain Security Assessment

### Lockfile & Install
- [status] Lockfile committed and CI uses frozen install
- [status] Install scripts reviewed

### CI/CD
- [status] Actions pinned to SHA
- [status] Minimal workflow permissions
- [finding] PR workflow exposes secrets — details

### Dependencies
- [finding] Package X has suspicious postinstall script
- [finding] Unscoped internal package name collision risk

### Recommendations
1. Add `npm ci --ignore-scripts` to CI, allowlist safe scripts
2. Pin GitHub Actions to commit SHAs
3. Enable npm provenance for published packages
```

## Incident Response

If a compromised package is detected:
1. **Stop** — remove package, block in `.npmrc`
2. **Assess** — check logs for exfiltration, rotate all secrets
3. **Notify** — security team, affected users
4. **Remediate** — clean install from lockfile, audit git history
5. **Prevent** — add package to deny list, improve review process

