Summary
zizmor (v1.24.1) currently reports 22 template-injection findings across 4 workflow files under .github/workflows/. Template-injection happens when a GitHub Actions ${{ … }} expression is interpolated directly into a shell run: block, where an attacker-controlled or weakly-validated value can be expanded as code. The canonical fix is to move every dynamic value into a step-level env: block and reference it via $VAR (or "${VAR}") from the script.
This issue tracks every finding location so they can be closed out systematically.
Full zizmor output summary
123 findings (2 ignored, 101 suppressed, 20 fixable): 12 informational, 0 low, 5 medium, 3 high
The template-injection subset (22 sites) broken down by file:
.github/workflows/openclaw-cross-os-release-checks-reusable.yml — 12 sites
Lines 441:90, 442:38, 443:31, 444:34, 445:37, 446:88, 447:29, 448:25, 449:26, 450:24, 452:77, 452:105.
Owner / PR in flight:
.github/workflows/docker-release.yml — 6 sites (unowned)
- Line 367:36 —
mapfile -t tags <<< "${{ steps.tags.outputs.value }}"
- Line 374:17 —
${{ needs.build-amd64.outputs.digest }}
- Line 375:17 —
${{ needs.build-arm64.outputs.digest }}
- Line 381:36 —
mapfile -t tags <<< "${{ steps.tags.outputs.slim }}"
- Line 388:17 —
${{ needs.build-amd64.outputs.slim-digest }}
- Line 389:17 —
${{ needs.build-arm64.outputs.slim-digest }}
All in the create-manifest job (Create and push default manifest and Create and push slim manifest steps). Fix: hoist each expression into the step's env: block, reference as $VAR in the shell.
.github/workflows/openclaw-npm-release.yml — 1 site (unowned)
- Line 402:31 —
publish_target="${{ steps.publish_tarball.outputs.path }}" in the Publish step. Fix: add PUBLISH_TARGET: ${{ steps.publish_tarball.outputs.path }} to the step env: block and use "${PUBLISH_TARGET}" in the script.
.github/workflows/control-ui-locale-refresh.yml — 1 site (unowned)
- Line 143:78 —
--locale "${{ matrix.locale }}" in the Refresh control UI locale files step. Fix: add LOCALE: ${{ matrix.locale }} to the step env: block and use "${LOCALE}".
Non-template-injection findings
Out of scope for this issue but worth tracking separately:
unpinned-uses (various) — third-party actions pinned by tag instead of commit digest.
artipacked, cache-poisoning, etc. — surfaced by zizmor --persona auditor (stricter mode).
Acceptance criteria
References
Summary
zizmor(v1.24.1) currently reports 22template-injectionfindings across 4 workflow files under.github/workflows/. Template-injection happens when a GitHub Actions${{ … }}expression is interpolated directly into a shellrun:block, where an attacker-controlled or weakly-validated value can be expanded as code. The canonical fix is to move every dynamic value into a step-levelenv:block and reference it via$VAR(or"${VAR}") from the script.This issue tracks every finding location so they can be closed out systematically.
Full zizmor output summary
123 findings (2 ignored, 101 suppressed, 20 fixable): 12 informational, 0 low, 5 medium, 3 highThe template-injection subset (22 sites) broken down by file:
.github/workflows/openclaw-cross-os-release-checks-reusable.yml— 12 sitesLines 441:90, 442:38, 443:31, 444:34, 445:37, 446:88, 447:29, 448:25, 449:26, 450:24, 452:77, 452:105.
Owner / PR in flight:
fix(ci): harden release checks workflow inputs(alexlomt) — covers every site in this file using the env-var-substitution pattern. Currently open; recommended to merge first.CI: fix matrix lane shell interpolation in release checks(hxy91819) — overlapping fix bundled with an unrelatedscripts/openclaw-cross-os-release-checks.tsrefactor. Recommended to rebase after fix(ci): harden release checks workflow inputs #66884 and drop the workflow-YAML changes..github/workflows/docker-release.yml— 6 sites (unowned)mapfile -t tags <<< "${{ steps.tags.outputs.value }}"${{ needs.build-amd64.outputs.digest }}${{ needs.build-arm64.outputs.digest }}mapfile -t tags <<< "${{ steps.tags.outputs.slim }}"${{ needs.build-amd64.outputs.slim-digest }}${{ needs.build-arm64.outputs.slim-digest }}All in the
create-manifestjob (Create and push default manifestandCreate and push slim manifeststeps). Fix: hoist each expression into the step'senv:block, reference as$VARin the shell..github/workflows/openclaw-npm-release.yml— 1 site (unowned)publish_target="${{ steps.publish_tarball.outputs.path }}"in thePublishstep. Fix: addPUBLISH_TARGET: ${{ steps.publish_tarball.outputs.path }}to the stepenv:block and use"${PUBLISH_TARGET}"in the script..github/workflows/control-ui-locale-refresh.yml— 1 site (unowned)--locale "${{ matrix.locale }}"in theRefresh control UI locale filesstep. Fix: addLOCALE: ${{ matrix.locale }}to the stepenv:block and use"${LOCALE}".Non-template-injection findings
Out of scope for this issue but worth tracking separately:
unpinned-uses(various) — third-party actions pinned by tag instead of commit digest.artipacked,cache-poisoning, etc. — surfaced byzizmor --persona auditor(stricter mode).Acceptance criteria
template-injectionfindings resolved.zizmor .github/workflows/reports 0template-injectionfindings under the defaultregularpersona.References
template-injectionaudit docs