Harden the OpenCode bump workflow against shell injection from a release tag

Merged
AF
20h ago
+38-8

The weekly OpenCode bump workflow read the latest anomalyco/opencode release tag and pasted it into shell source through ${{ steps.latest.outputs.version }}. Git tag names may contain $, (, ; and backticks, so a hostile upstream tag could run code in a job holding contents: write and pull-requests: write. Found by the supply-chain audit of PR #985 (it predates that PR).

  • Both the current pin and the upstream version must match strict semver (X.Y.Z or X.Y.Z-prerelease) before they reach GITHUB_OUTPUT.
  • Every later use goes through env: and a quoted variable; no ${{ }} expression remains inside a run: script.
  • actions/checkout uses persist-credentials: false; the PR step already pushes with its own minted app token.
  • actions/checkout and actions/create-github-app-token are pinned to commit SHAs.

Verified: a bash harness runs the workflow's producer scripts and rejects 1.2.3;id, 1.2.3$(id) and 1.2.3`id` while accepting 1.14.39 and 2.0.0-beta.1. With the guards removed, all 9 rejection checks fail. All 7 run scripts pass bash -n.


Summary by cubic

Harden the weekly OpenCode bump workflow so hostile anomalyco/opencode release tags can no longer inject shell commands into a job holding contents: write and pull-requests: write. Tag names, which may contain $, (, ;, and backticks, were previously interpolated into run: scripts without validation.

  • Both the current pin and the upstream version must match strict semver (X.Y.Z or X.Y.Z-prerelease) before use.
  • All version values now flow through quoted env: variables; no ${{ }} expression remains inside a run: script.
  • Pins actions/checkout and actions/create-github-app-token to commit SHAs.
  • Sets persist-credentials: false on checkout; the PR step already pushes with its own minted app token.
  • Adds a CI-only search descriptor; a bash harness rejects 1.2.3;id, 1.2.3$(id), and 1.2.3`id` while accepting 1.14.39 and 2.0.0-beta.1.