From 05fb5676f16d4c446105e3a2ac33dff1335d6b9c Mon Sep 17 00:00:00 2001 From: vivekchand Date: Sat, 29 Aug 2026 21:43:01 +0000 Subject: [PATCH] Harden CI: bind matrix.source before it reaches the smoke-test shell The "Install into isolated venv" step interpolated ${{ matrix.source }} directly into its run: block. GitHub substitutes ${{ }} expressions textually, before bash parses the line, so the value arrives as script source rather than as data and the surrounding quotes give no protection. zizmor reports this as template-injection (Medium) -- the last non-informational finding of that family in the repository. Nothing is reachable through it today, and this is defence in depth rather than a fix for an exploitable path: the matrix is closed, because both fromJSON arrays feeding `source` are literals, so the value can only ever be the string "wheel" or "pypi". Binding it keeps that true if the matrix later starts deriving its value from a workflow input or an event payload, which is the change that would otherwise turn this line into a live injection site without anyone editing it. The value now travels through a step-level env: var and is read as a quoted shell variable. The other two references (the job `name:` and the step `if:`) are expression contexts, not shell, and are left as they are. Verified: all 35 workflow and composite-action files parse; zizmor on this file goes 1 -> 0 findings; and the run block was executed under `bash -e` with a stubbed pip for both matrix values -- resolved argv is byte-identical to the old form in each case (wheel -> local dist wheel, pypi -> --no-cache-dir from PyPI). No-PRD: CI-only change under .github/, exempt from the product-record gate. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FcrEBdhyYY8etBZMtAL6UK --- .github/workflows/api-latency-smoke.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/api-latency-smoke.yml b/.github/workflows/api-latency-smoke.yml index 0e16aa0584..eecb34c72b 100644 --- a/.github/workflows/api-latency-smoke.yml +++ b/.github/workflows/api-latency-smoke.yml @@ -52,10 +52,19 @@ jobs: python -m build --wheel - name: Install into isolated venv + # `matrix.source` is bound to an env var rather than expanded into the + # script. GitHub substitutes `${{ }}` textually before bash parses the + # line, so an expression in a run: block is script source, not data -- + # the surrounding quotes give no protection. This matrix is closed + # (both fromJSON arrays above are literals), so nothing here is + # reachable today; binding it keeps that true if the matrix ever + # starts deriving a value from an input or event payload. + env: + SOURCE: ${{ matrix.source }} run: | python -m venv /tmp/vsmoke /tmp/vsmoke/bin/pip install --upgrade pip - if [ "${{ matrix.source }}" = "pypi" ]; then + if [ "$SOURCE" = "pypi" ]; then /tmp/vsmoke/bin/pip install --no-cache-dir clawmetry flask waitress cryptography duckdb requests else /tmp/vsmoke/bin/pip install dist/clawmetry-*.whl flask waitress cryptography duckdb requests