Skip to content

fix(ci): pin actions to SHAs and harden injection-prone workflows#2602

Open
fahreddinozcan wants to merge 1 commit into
masterfrom
ctx7-1641-github-actions-hardening
Open

fix(ci): pin actions to SHAs and harden injection-prone workflows#2602
fahreddinozcan wants to merge 1 commit into
masterfrom
ctx7-1641-github-actions-hardening

Conversation

@fahreddinozcan
Copy link
Copy Markdown
Contributor

@fahreddinozcan fahreddinozcan commented May 12, 2026

Summary

Closes the 10 MEDIUM GitHub-Actions findings from a deepsec scan.

  • Pin every action to a commit SHA across all 6 workflows. Mutable tags can be re-pointed (see tj-actions/changed-files, March 2025) — SHAs can't.
  • Fix ${{ inputs.version }} script injection in ecr-deploy.yml (AWS keys in scope) and mcp-registry.yml (id-token: write in scope). Both now route through env: vars + a semver regex.
  • Verify the mcp-publisher binary before executing: pinned to v1.4.0, sha256sum -c - checked against the release SHA-256.
  • Move ~/.npmrc write to after pnpm install in release.yml and canary-release.yml so NPM_TOKEN isn't readable by dependency lifecycle scripts.

Test plan

  • Test workflow passes on this PR
  • After merge, dispatch Canary Release once to confirm publish still works with the relocated auth step
  • After merge, dispatch Publish to MCP Registry once to confirm the checksum-verify + extraction path

Notes

  • May need the skip-changeset label (CI-only, no package impact).
  • pnpm/action-setup is pinned to what @v4 currently resolves to (b906affc..., a post-v4.4.0 revert by the maintainer). Comment is # v4 because the SHA isn't a named release.

Pin every third-party and first-party action across all 6 workflows to
a full commit SHA (with a version comment), so a compromised action tag
can no longer alter what runs in jobs that hold NPM_TOKEN, AWS keys, or
OIDC. Same pattern recommended by GitHub's hardening docs and OpenSSF.

Other fixes in scope:

- ecr-deploy.yml: route inputs.version and steps.build-push.outputs.digest
  through env: vars in the GITHUB_STEP_SUMMARY step so neither is evaluated
  as shell. Quote $GITHUB_STEP_SUMMARY.

- mcp-registry.yml: route inputs.version through an env var, validate
  against a semver regex, and read VERSION via shell ($VERSION from
  $GITHUB_ENV) rather than re-interpolating ${{ env.VERSION }}. Replace
  the lossy 'echo \$(jq ...) > server.json' pattern with a temp file +
  mv. Pin the mcp-publisher binary to v1.4.0 and verify its SHA-256
  before extraction. Hardcode linux/amd64 since runs-on is ubuntu-latest.

- canary-release.yml / release.yml: move 'Configure npm authentication'
  from before 'pnpm install' to right before the publish step. NPM_TOKEN
  is no longer present in ~/.npmrc while dependency lifecycle scripts
  run, so a compromised dep or attacker-influenced branch cannot exfil
  the publish token via preinstall/postinstall.

Net: closes the 10 MEDIUM GitHub-Actions findings from the deepsec scan
(2x rce, 6x unpinned-actions, 1x untrusted-branch-checkout, 1x
unverified-binary-download).
@linear
Copy link
Copy Markdown

linear Bot commented May 12, 2026

CTX7-1641

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants