$0 Supply-Chain Security Lab

Harshit KocharHarshit Kochar
5 min read

Summary — I hardened a tiny Node.js repo using only free tooling: PR gates (branch protection, Dependency Review, secrets scanning), repo posture checks (OpenSSF Scorecard), SBOM + vulnerability gating (Syft → CycloneDX + Grype), and verifiable build provenance (GitHub Artifact Attestations).
I then broke it on purpose to prove the controls work and made those checks blocking.
The “why” maps to NIST SSDF and SLSA.

Github repo: https://github.com/prorajnikant/scs


Who this helps

Teams shipping on GitHub who want practical guardrails now: PR-time blocking for risky changes, SBOM + vuln gating to stop bad builds, and provenance so you can prove where builds came from. This lines up with SSDF’s secure dev practices and SLSA’s build integrity model.


The mental model (one minute)

  • SSDF (NIST SP 800-218) is the checklist of secure-dev practices (source integrity, dependency risk, build integrity). It tells you what to do, not the exact how.
    Source: NIST SP 800-218 — SSDF v1.1

  • SLSA v1 “Provenance” standardizes the signed, verifiable facts about who/what/where/how built your artifact—evidence you can validate in pipelines.
    Source: SLSA v1 — Provenance


What I built (Node.js repo)

  1. PR gates

    • Branch protection on main → require PRs, approvals, and (later) required status checks.

    • Dependency Review on every PR → blocks adding known-vulnerable packages and shows impact right in the diff.

    • Secrets scanning with Gitleaks (free) on push/PR.

  2. Posture checks

    • OpenSSF Scorecard GitHub Action → flags repo-hygiene issues (e.g., missing SECURITY.md, unpinned actions) and surfaces results in the Security tab.
  3. SBOM + vulnerability gating

    • Generate a CycloneDX SBOM with Syft and scan it with Grype; fail High/Critical. CycloneDX is a full-stack BOM standard (ECMA-424).
  4. Build provenance (SLSA-style)

    • Emit GitHub Artifact Attestations from Actions and verify them later.
  5. Workflow hardening

    • Pin actions to a full commit SHA and scope GITHUB_TOKEN to least-privilege at job/workflow level.

Node.js reproducibility tip: use npm ci (not npm install) in CI for deterministic installs from package-lock.json.


Day 1 — Source & PR gatekeeping

1) Lock down the repo

  • Turn on Branch protection for main → require PRs + approvals (e.g., ≥1), and add Required status checks.

  • Add SECURITY.md and CODEOWNERS (GitHub looks for CODEOWNERS in .github/, then repo root, then /docs).

2) Make the review smarter (free)

  • Enable Dependency Review so PRs that introduce vulnerable deps fail.

  • Add Gitleaks to catch leaked secrets.

  • Add OpenSSF Scorecard for repo hygiene signals in the Security tab.

3) Deterministic Node installs

  • In CI, run npm ci (enforces lockfile; ideal for CI). Optionally add npm audit.

Day 2 — Build integrity & transparency

4) SBOM + vuln gating

  • Use Syft → output CycloneDX JSON.

  • Use Grype → fail the build on High/Critical.

5) Provenance (SLSA)

  • Enable Artifact Attestations in Actions to establish and later verify build provenance.

6) Harden the pipeline itself

  • Pin actions to SHAs; reduce default token scopes; set explicit permissions: per job.

Day 3 — Break-glass drills, enforcement, and proof

7) Prove the controls work

  • Open a PR that bumps a dependency to a known-vulnerable version → Dependency Review should fail.

  • Commit a benign fake secret on a throwaway branch → Gitleaks should fail.

  • Trigger a build → verify your attestation in the Attestations UI or via CLI.

8) Make it stick

  • Mark your CI jobs (Scorecard, Dependency Review, Secrets, SBOM/Grype, Attestations) as Required status checks under branch protection.

Results (what changed and why it matters)

ControlWhat I enforcedProofStandard tie-in
PR gatesReviews + required checks + dep diff + secret scanningBlocked PR + failed secret checkSSDF: secure source & dependency mgmt; PR-time risk reduction
SBOM + vuln gatingCycloneDX SBOM; fail on High/CriticalSBOM artifact + Grype runCycloneDX spec + vulnerability mgmt
ProvenanceArtifact Attestations on buildAttestation UI + verificationSLSA v1 provenance

Reproduce this (copy-paste checklist)

  • [ ] Enable branch protection; add CODEOWNERS & SECURITY.md.

  • [ ] Add Dependency Review, Gitleaks, OpenSSF Scorecard on PR/push.

  • [ ] Use npm ci in CI for reproducible installs; optionally npm audit.

  • [ ] Generate CycloneDX SBOM with Syft; scan the generated SBOM with Grype; fail on High/Critical.

  • [ ] Emit Artifact Attestations (provenance) for your build; verify one.

  • [ ] Pin Actions to SHAs and reduce GITHUB_TOKEN permissions per job.

  • [ ] Mark all CI jobs as Required status checks.


Notes & gotchas (worth your time)

  • Two branch-protection toggles that look similar but behave differently:
    Dismiss stale approvals when new commits are pushed vs Require approval of the most recent reviewable push. The first dismisses prior approvals when the PR diff changes; the second ensures someone other than the last pusher re-approves without necessarily wiping other approvals. Choose based on your threat model.

  • Where GitHub looks for CODEOWNERS: .github/, then repo root, then /docs. Handy when debugging non-triggering owners.

  • Scorecard and branch protection: If you’re using classic Branch Protection rules, Scorecard’s Action may not read them with the default token. Consider Repository Rules or a PAT per docs.

  • Cross-workflow artifacts: Downloading artifacts across workflows/repos requires passing a token to actions/download-artifact; relying on default scoping won’t work.

  • CycloneDX is more than “just SBOM”: it models services, relationships, pedigree, and can carry declarations/attestations too—that’s why I chose it.

  • SLSA provenance: it’s a signed statement of how something was built; it doesn’t assert that software is “secure,” but it gives consumers what they need to verify & enforce policy.


References

0
Subscribe to my newsletter

Read articles from Harshit Kochar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harshit Kochar
Harshit Kochar

Curios about anything security or engineering. Learning to ask deeper and difficult questions. Happy-go-lucky :)