Supply-chain checks that actually catch things
I am tired of reading vendor pitches that begin “In 2024, supply-chain attacks rose 742%.” The number is probably correct. The recommendation that follows it is almost always to buy something. Here is what I actually run, what it has caught, and what I have stopped bothering with.
The short list
osv-scanneron the lockfile, on every PR, blocking on critical CVEs only.cosign verifyon every base image we pull, against a pinned set of issuers.- A diff of
package-lock.jsonthat flags any new package whose first version was published less than 14 days ago. - Build provenance via SLSA level 2 with GitHub OIDC. Cheap and worth it.
What the 14-day rule caught
Twice in the last year, a typosquat showed up in a transitive dep update. Both were caught by the publication-age check, neither was on any CVE feed at the time, and both were yanked from npm within 48 hours of us flagging.
#!/usr/bin/env bash
set -euo pipefail
# Print packages added or upgraded in this PR whose first publish was <14 days ago.
base="${1:-origin/main}"
git show "${base}":package-lock.json > /tmp/old.json
jq -r '.packages | to_entries[] | "\(.key)\t\(.value.version // "")"' package-lock.json \
| while IFS=$'\t' read -r pkg ver; do
[[ -z "$ver" ]] && continue
old_ver=$(jq -r --arg k "$pkg" '.packages[$k].version // ""' /tmp/old.json)
[[ "$old_ver" == "$ver" ]] && continue
name="${pkg#node_modules/}"
published=$(curl -fsSL "https://registry.npmjs.org/${name}" \
| jq -r --arg v "$ver" '.time[$v] // empty')
[[ -z "$published" ]] && continue
age=$(( ( $(date +%s) - $(date -d "$published" +%s) ) / 86400 ))
if (( age < 14 )); then
echo "NEW: ${name}@${ver} published ${age}d ago"
fi
done
What I dropped
Full SBOM generation on every build, indexed somewhere nobody reads. We keep one for the release artifact and that is it. The CI minutes are better spent on the publication-age check above.
: : :