# Supply Chain Security Checklist for Dependency Changes

When a PR adds a new dependency or bumps an existing one, review the upstream release for supply chain risk. Real-world incidents (e.g., LiteLLM 1.82.7-1.82.8 in March 2026, PyTorch Lightning 2.6.2-2.6.3 in April 2026) show that trusted packages can be hijacked through compromised CI/CD pipelines, stolen publishing credentials, or poisoned build artifacts - with malicious code present only in the published package, not in the source repository.

## Risk-Based Scrutiny Tiers

Release recency is the primary risk signal - even widely-used, established packages can be compromised (e.g., LiteLLM was a popular package with high download counts when it was hijacked). Check when the target version was published before choosing a tier.

**Apply full scrutiny** (all checks below) when:
- The target version was published less than 7 days ago - regardless of package popularity or age, except first-party packages maintained by the same organization as the reviewed repository. First-party packages are intentionally excluded from the 7-day waiting rule: do not block solely on freshness, but still scrutinize them for supply-chain risk using this checklist. For PyPI: visit `https://pypi.org/project/<package>/<version>/` and check the "Released" date. For npm: run `npm view <package>@<version> time`. Recent releases have not had time for community vetting, and this is exactly the window supply chain attackers exploit.
- Adding a dependency not previously used in this project
- Upgrading a package that was first published less than 6 months ago (check oldest version at `https://pypi.org/project/<package>/#history` or `npm view <package> time | head -3`) or has low weekly downloads (for PyPI: check `https://pypistats.org/packages/<package>` for weekly downloads; for npm: see weekly downloads on the package page at `https://www.npmjs.com/package/<package>`; use <10k on PyPI / <1k on npm as thresholds)
- The dependency includes native code, install hooks, or system-level access

**Apply standard scrutiny** (limited checks) when:
- Upgrading to a version that has been published for at least 7 days, from a widely-used, established package with high adoption (>=10k weekly downloads on PyPI / >=1k on npm; e.g., pytest, requests, react, lodash)
- Minor or patch version bumps to packages with a history of regular releases, where the target version is at least 7 days old
- **Check only**: downgrades, yanked versions (target or recent versions), and presence of release notes/source tags. If you find downgrades or high-severity signals (yanked versions), immediately switch to full scrutiny and apply all checklist items below. If you find medium-severity signals (missing release notes) without other signals, note them but remain in standard scrutiny unless combined with additional concerns.

## Checklist

- **Release note and changelog gaps**: Verify a source tag exists for the version. Check `https://github.com/<org>/<repo>/releases/tag/v<version>` or run `gh release view v<version> --repo <org>/<repo>`. If there is no tag, no release notes, or an empty changelog, this is a medium-severity signal - note it in your review and escalate if the package is under full scrutiny or if combined with other signals from this checklist.
- **Yanked or retracted versions**: Check if the target version or nearby versions have been yanked. For PyPI: `pip index versions <package>` (yanked versions are marked with `[yanked]`). For npm: check the registry page at `https://www.npmjs.com/package/<package>/v/<version>` to see if the version is deprecated, or run `npm view <package>@<version>` (shows `deprecated` field if present). Yanked versions - whether the target or recent neighboring versions - indicate the maintainer or registry identified a problem. Investigate whether it was a security incident or a routine bad release. If any version in the range was yanked for security reasons, treat as a high-severity signal.
- **Brand-new releases with no adoption signal**: Check when the version was published. For PyPI: visit `https://pypi.org/project/<package>/<version>/` and check the "Released" date. For npm: run `npm view <package>@<version> time`. If published within the last 48 hours and the package is under full scrutiny (or combined with other signals per the escalation guidance below), flag it as elevated risk. Adoption signals include: download counts visible on the registry page, discussion or announcements in the project's issue tracker, mentions in security monitoring feeds (e.g., Snyk, Socket, OSV), or endorsements from maintainers in community channels.
- **Source-to-package divergence**: If other signals raise concern, compare the published artifact against the source. For PyPI: download the sdist/wheel from `https://pypi.org/project/<package>/<version>/#files`, extract it, clone the tagged source (`git clone --branch v<version> --depth 1 <repo-url>`), and diff: `diff -r <extracted-package>/ <repo-clone>/`. For npm: run `npm pack <package>@<version>`, extract with `tar -xzf <package>-<version>.tgz`, clone source, and compare: `diff -r package/ <repo-clone>/`. Focus your review on source files (.py for Python, .js/.ts for npm) rather than build artifacts or package metadata. Adjust paths to match the package's source layout (commonly `src/`, `lib/`, or root). Divergence in source files is a strong indicator of tampering. Request that the PR author verify and document provenance.
- **Unusual install-time behavior**: Watch for new post-install scripts, `.pth` files, or import-time side effects introduced by the dependency update. For npm: check for `preinstall`/`postinstall` scripts in the package's `package.json`. For Python: look for `setup.py` with code execution or `.pth` files in the distribution. These are common payload delivery mechanisms in supply chain attacks.
- **Cascading dependency risk**: If other signals raise concern about a dependency, check whether that dependency's own upstream dependencies have active advisories. For each upstream dependency, search `https://osv.dev/list?q=<upstream-dep-name>` or `https://security.snyk.io/package/pip/<upstream-dep-name>` (or `/npm/<upstream-dep-name>`) for known vulnerabilities. A compromised upstream tool (e.g., a CI/CD scanner or build plugin) can be used to steal publishing credentials for downstream packages.

## Escalation Guidance

Escalate to 🔴 High Risk if any high-severity signal is present: yanked/retracted versions, source-to-package divergence, or new install-time behavior (post-install scripts, `.pth` files). For medium-severity signals (brand-new release with no adoption signal, missing release notes), escalate only when combined with other signals from this checklist (medium or high severity) or when the package is under full scrutiny. If a dependency is under full scrutiny solely because the target version is newer than 7 days, do **NOT** approve until it is at least 7 days old unless it is first-party; after that, re-evaluate it using the rest of this checklist. For first-party packages, do not block solely on freshness, but still document the supply-chain risk review. For dependencies under standard scrutiny, brand-new publication alone is not sufficient to escalate - established packages with frequent release cycles routinely publish new versions.
