Skip to content

fix(ci): harden release workflows against expression injection + SHA-pin actions#37

Merged
chaodu-agent merged 1 commit into
mainfrom
fix/release-workflows-injection
Jul 14, 2026
Merged

fix(ci): harden release workflows against expression injection + SHA-pin actions#37
chaodu-agent merged 1 commit into
mainfrom
fix/release-workflows-injection

Conversation

@chaodu-agent

Copy link
Copy Markdown
Contributor

What

Hardens release-pr.yml and release.yml against expression injection, and SHA-pins two third-party actions. Found during a workflow-security audit across oablab/chi, oablab/ecsctl, and openabdev/ghpool (companion of openabdev/openab#1393/#1395/#1396, which fixed the identical pattern in openab's release-pr.yml).

Injection fix

${{ inputs.version }}, ${{ inputs.tag }}, and ${{ steps.*.outputs.* }} were expanded directly inside run: shell blocks across five jobs (resolve-version, create-release, build, docker, docker-manifest). GitHub Actions expands ${{ }} before bash parses the script, so a crafted version/tag string can break out of the shell string context.

Threat model: release-pr.yml is workflow_dispatch-only (requires repo write access, and carries an App token with contents: write + pull-requests: write). release.yml also triggers on push: tags, itself gated on write access. Same insider/leaked-credential threat model as openab's release-pr.yml — not an open attack surface, but the same class of footgun.

Fix: every inputs.*/steps.*.outputs.* reference in a run: block now goes through env: and is referenced as "$VAR" in shell. No behavioral change.

SHA-pinning

dtolnay/rust-toolchain@stable and Swatinem/rust-cache@v2 are pinned to the commit SHA their tag/branch currently resolves to, across ci.yml, e2e.yml, and release.yml — same rationale as openabdev/openab#1396: a mutable tag or branch ref can be moved by anyone with push access to the upstream action repo; a commit SHA cannot. Version kept as a trailing comment.

Verification

  • YAML parses cleanly on all 4 modified files
  • actionlint clean (exit=0)
  • Scanner confirms zero remaining tainted interpolation (inputs.*, steps.*.outputs.*) in run: blocks
  • No behavior change: every SHA is the exact commit the previous tag/branch pointed to at time of audit

…pin actions

Follow-up to a workflow-security audit across oablab/chi, oablab/ecsctl,
and openabdev/ghpool (companion of openabdev/openab#1393/#1395/#1396,
which fixed the same pattern in openab's release-pr.yml).

release-pr.yml and release.yml expanded ${{ inputs.version }},
${{ inputs.tag }}, and ${{ steps.*.outputs.* }} directly inside run:
shell blocks across five jobs (resolve-version, create-release, build,
docker, docker-manifest). Actions expands ${{ }} before bash ever sees
the script, so a crafted version/tag string can break out of the shell
string context.

Threat model: release-pr.yml is workflow_dispatch-only (requires repo
write access + carries an App token with contents:write +
pull-requests:write via steps.app-token.outputs.token). release.yml
triggers on 'push: tags' too, which is also gated on write access to
push a tag. Same insider/leaked-credential threat model as openab's
release-pr.yml.

Fix: every inputs.*/steps.*.outputs.* reference in a run: block now
goes through env: and is referenced as "$VAR" in shell, matching the
canonical pattern already applied across openab's workflows. No
behavioral change.

Also SHA-pins dtolnay/rust-toolchain@stable and Swatinem/rust-cache@v2
across ci.yml, e2e.yml, and release.yml (same rationale as
openabdev/openab#1396: a mutable tag/branch ref can be moved by anyone
with push access to the upstream action repo; a commit SHA cannot).
Version kept as a trailing comment for readability.
@chaodu-agent chaodu-agent merged commit 5d7473e into main Jul 14, 2026
@chaodu-agent chaodu-agent deleted the fix/release-workflows-injection branch July 14, 2026 00:08
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