Summary
The release workflow embeds ${{ github.ref_name }} directly inside a run: Bash block. GitHub Actions expression expansion occurs before the shell parses the script, so a syntactically valid tag name containing shell metacharacters — e.g. v1.2.$(id) — causes command substitution to execute on the runner. The vulnerable step runs with contents: write and exposes GITHUB_TOKEN/GH_TOKEN, so any user able to push a matching tag could execute arbitrary commands in the release job, exfiltrate the token during its lifetime, or tamper with release publication.
Affected commit: 45e3bde
Reported via: PR #323
Evidence
.github/workflows/release.yml lines 4–7: workflow triggers on tag pushes matching v*.*.*; this glob pattern matches tag names that include $() shell metacharacters.
- Lines 118–121: the release job is granted
contents: write.
- Lines 129–142:
${{ github.ref_name }} is interpolated directly into a Bash run: script while GITHUB_TOKEN and GH_TOKEN are set as environment variables.
Validation confirmed:
git check-ref-format refs/tags/v1.2.$(printenv>leaked_env) returns success — the crafted tag is accepted by Git ref syntax.
- A local emulation of the vulnerable step executed the command substitution and produced a
leaked_env file containing the fake token values; the safe env-var variant did not.
Attack Path
- Attacker (or compromised trusted account) creates/pushes a tag matching
v*.*.* whose name includes shell metacharacters.
- The release job triggers; GitHub Actions expands
${{ github.ref_name }} into the Bash script before the shell parses it.
- Command substitution executes on the GitHub Actions runner in a step that holds
GITHUB_TOKEN/GH_TOKEN and contents: write.
- Attacker can exfiltrate the ephemeral token, create or tamper with releases, or inject malicious artifacts into the release pipeline.
Severity
High — exploitation requires repository tag-push capability or a compromised trusted account; the token appears scoped to this repository rather than broader organisation credentials. Impact is nonetheless high: arbitrary runner command execution, release integrity compromise, and potential supply-chain risk for consumers of published release artefacts.
Recommended Fix
Pass the tag name through an environment variable and reference it as "$TAG_NAME" in the shell script rather than interpolating the Actions expression directly. Optionally, add strict validation (e.g. a regex guard) before any shell use of the tag name.
Controls Already Present
- Repository authentication is required to push tags.
- Top-level workflow permissions are
contents: read; the release job explicitly elevates.
- Shared actions are pinned to commit SHAs.
- Pull-request dry-run workflow sets
contents: read and passes dry-run: true.
Blindspots
- Live GitHub tag protection/ruleset configuration was not confirmed via static review.
- Downstream adoption of published release artefacts determines the full supply-chain blast radius.
Reported by @leynos.
Summary
The release workflow embeds
${{ github.ref_name }}directly inside arun:Bash block. GitHub Actions expression expansion occurs before the shell parses the script, so a syntactically valid tag name containing shell metacharacters — e.g.v1.2.$(id)— causes command substitution to execute on the runner. The vulnerable step runs withcontents: writeand exposesGITHUB_TOKEN/GH_TOKEN, so any user able to push a matching tag could execute arbitrary commands in the release job, exfiltrate the token during its lifetime, or tamper with release publication.Affected commit: 45e3bde
Reported via: PR #323
Evidence
.github/workflows/release.ymllines 4–7: workflow triggers on tag pushes matchingv*.*.*; this glob pattern matches tag names that include$()shell metacharacters.contents: write.${{ github.ref_name }}is interpolated directly into a Bashrun:script whileGITHUB_TOKENandGH_TOKENare set as environment variables.Validation confirmed:
git check-ref-format refs/tags/v1.2.$(printenv>leaked_env)returns success — the crafted tag is accepted by Git ref syntax.leaked_envfile containing the fake token values; the safe env-var variant did not.Attack Path
v*.*.*whose name includes shell metacharacters.${{ github.ref_name }}into the Bash script before the shell parses it.GITHUB_TOKEN/GH_TOKENandcontents: write.Severity
High — exploitation requires repository tag-push capability or a compromised trusted account; the token appears scoped to this repository rather than broader organisation credentials. Impact is nonetheless high: arbitrary runner command execution, release integrity compromise, and potential supply-chain risk for consumers of published release artefacts.
Recommended Fix
Pass the tag name through an environment variable and reference it as
"$TAG_NAME"in the shell script rather than interpolating the Actions expression directly. Optionally, add strict validation (e.g. a regex guard) before any shell use of the tag name.Controls Already Present
contents: read; the release job explicitly elevates.contents: readand passesdry-run: true.Blindspots
Reported by @leynos.