Skip to content

security: harden CI/CD pipeline against supply chain attacks#20

Open
ajag408 wants to merge 4 commits into
mainfrom
security/eng-2688-ci-supply-chain-hardening
Open

security: harden CI/CD pipeline against supply chain attacks#20
ajag408 wants to merge 4 commits into
mainfrom
security/eng-2688-ci-supply-chain-hardening

Conversation

@ajag408
Copy link
Copy Markdown
Contributor

@ajag408 ajag408 commented May 14, 2026

Motivation

The TanStack/Mini Shai-Hulud supply chain attack (May 2026) compromised 169 npm packages by poisoning GitHub Actions caches via PR CI runs, then publishing malicious packages through trusted release workflows.

Shield's build-binaries job shared a pnpm store cache between PR CI runs and release builds — the same vector TanStack was exploited through. Since Trust will consume the SEA binary directly, the entire build pipeline must be hardened before the next release tag.

The monorepo already has most of these layers (Socket Firewall, harden-runner, persist-credentials). This PR brings Shield to parity and adds install-time controls the monorepo should also adopt.

Changes

Install-time hardening

Change File Why
Remove enable-pre-post-scripts=true .npmrc Today every dependency can run arbitrary code on install. This is the exact mechanism Mini Shai-Hulud uses (preinstall, prepare hooks). Removing it blocks all lifecycle scripts by default.
Add onlyBuiltDependencies: ["esbuild"] package.json Allowlist for packages permitted to run postinstall. Only esbuild needs it (downloads platform binary). Everything else blocked.
Add minimum-release-age=4320 .npmrc 3-day publish cooldown. pnpm refuses package versions published less than 3 days ago. The TanStack malicious versions were all caught within hours — this would have blocked them.

Release-path hardening

Change File Why
Remove actions/cache from build-binaries release.yml Closes TanStack-class cache poisoning on the binary build path. publish job was already cache-free. ~30s slower, eliminates shared cache as attack vector.
Add NPM_CONFIG_PROVENANCE=true on publish release.yml Attaches SLSA provenance to the npm package. Matches the attest-build-provenance already done for binaries. Consumers can verify the package was built by our GitHub Actions workflow.

Detection

Change File(s) Why
Add step-security/harden-runner (audit mode) ci.yml + release.yml Egress auditing — logs all outbound network connections in every job. Catches exfiltration attempts. SHA-pinned to match monorepo (v2.16.1).
Add persist-credentials: false on all checkouts ci.yml + release.yml Prevents GITHUB_TOKEN from being persisted to .git/config. Matches monorepo.
Add Socket Firewall (socketdev/action) on all installs ci.yml + release.yml Install-time malware interception — checks every package against Socket's database before lifecycle scripts execute. Matches monorepo. Requires SOCKET_SECURITY_API_KEY repo secret (see below).
Add actions/dependency-review-action on PRs ci.yml Flags new dependencies or version changes that introduce known vulnerabilities. Runs on pull_request only.

Governance

Change File Why
Expand CODEOWNERS .github/CODEOWNERS Adds .npmrc, package.json, pnpm-lock.yaml to require review for supply-chain-critical files.

What's NOT changed

  • No validator logic changes
  • No package output changes (npm tarball identical)
  • All existing action SHA pins preserved (already good)
  • pnpm version stays at 10.12.2

Admin actions required

  1. Before CI can pass: set SOCKET_SECURITY_API_KEY as a repo secret (Settings → Secrets → Actions). Get the key from the monorepo's secrets or Socket dashboard.
  2. After merge: set branch protection on main and tag protection on v* (see Slack thread / PR comments for details).
  3. After merge: purge all GitHub Actions caches before tagging the next release.

Test plan

  • CI passes (harden-runner, Socket Firewall, dependency-review all active)
  • harden-runner egress logs visible in Actions run
  • Socket Firewall wraps install step (sfw visible in logs)
  • esbuild postinstall still runs (build succeeds despite onlyBuiltDependencies)
  • After merge: purge all caches, tag release, confirm build-binaries runs clean without cache
  • After merge: confirm npm package has provenance attached

Follow-up (separate PRs / settings)

  • Branch protection on main (require PR review + CI, no force-push)
  • Tag protection on v*
  • After 2-4 weeks of harden-runner audit logs: build egress allowlist, flip release.yml to egress-policy: block

Summary by CodeRabbit

  • Chores
    • Expanded supply-chain ownership for critical configuration files to improve accountability.
    • Hardened CI/CD workflows with runner and network protections, stricter dependency install flows, and added a dependency-review check for PRs.
    • Updated release pipeline to enforce provenance on published packages and apply the same hardening.
    • Refined package and npm settings to control dependency build behavior and release timing.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 349d268f-e743-482b-a4e5-6b17db5076f1

📥 Commits

Reviewing files that changed from the base of the PR and between dcb55de and 48c9fef.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/release.yml
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

Adds CODEOWNERS for manifest files, adjusts npm/pnpm configs, and hardens CI/release workflows by adding runner hardening, disabling persisted checkout credentials, routing installs through a socket firewall via Corepack, making critical audit non-fatal, and adding a PR-only dependency-review job.

Changes

Supply Chain Security Hardening

Layer / File(s) Summary
Code Ownership and Package Configuration
.github/CODEOWNERS, .npmrc, package.json
Adds owners for .npmrc, package.json, and pnpm-lock.yaml; removes enable-pre-post-scripts and sets minimum-release-age=4320 in .npmrc; adds pnpm.onlyBuiltDependencies = ["esbuild"] to package.json.
CI Workflow Hardening
.github/workflows/ci.yml
test and security jobs add step-security/harden-runner, set persist-credentials: false for checkout, install pnpm via Corepack, add Socket Firewall steps, switch installs to sfw pnpm install --frozen-lockfile, change Codecov filefiles, make critical pnpm audit non-fatal, and add a PR-only dependency-review job.
Release Workflow Hardening
.github/workflows/release.yml
Adds runner hardening and non-persistent checkout across release jobs, replaces pnpm setup with Corepack + Socket Firewall and sfw pnpm install --frozen-lockfile, removes pnpm cache/store logic in build-binaries, and sets NPM_CONFIG_PROVENANCE: "true" for publish.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • stakekit/shield#10: Modifies the same CI and release workflow files with similar hardening and pnpm/checkout changes.

Suggested reviewers

  • Philippoes
  • petar-omni
  • jdomingos
  • raiseerco

Poem

🐰 I marked the manifests with careful hops,

Firewalls hum while the runner stops.
Corepack wakes and installs with care,
Audits softened, provenance declared.
Hop, review, and publish — safe everywhere.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'security: harden CI/CD pipeline against supply chain attacks' accurately summarizes the main change, which involves implementing comprehensive security hardening measures against supply chain attacks across the CI/CD pipeline.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security/eng-2688-ci-supply-chain-hardening

Comment @coderabbitai help to get the list of available commands and usage tips.

@ajag408 ajag408 requested review from aditya172926 and auralshin May 14, 2026 06:54
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 42-48: The Socket Firewall steps ("Set up Socket Firewall" action
socketdev/action) and the "Install dependencies" run step must explicitly expose
the API key by adding the secret as an environment variable (e.g., add an env
mapping SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_SECURITY_API_KEY }} on the
Socket step and the run step that invokes `sfw pnpm install`) so the action and
`sfw` CLI can read it at runtime; replicate the same change for the security job
steps that run the firewall and `sfw` install. Ensure each step that invokes the
socket action or `sfw` commands has the env entry so the secret is available
during execution (and consider using workflow-level or job-level env if multiple
steps need it).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97609dfa-cad3-4dfe-959f-c25b5110aee0

📥 Commits

Reviewing files that changed from the base of the PR and between 46094dc and 791b5e9.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release.yml

Comment thread .github/workflows/ci.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant