From 671d1e7e60309305fc91a60e42d4b88968768b3c Mon Sep 17 00:00:00 2001 From: rldyourmnd Date: Mon, 24 Aug 2026 03:24:12 +0500 Subject: [PATCH] fix(actions): pass action_path through the environment like everything else MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling code scanning surfaced two `actions/code-injection` findings, one in each composite action, both on the same line: root="$(cd -- "${{ github.action_path }}/../../.." && pwd)" Every other value these two files use — command, plan, state, target, output, at, operation — is already passed through `env:` and read as a shell variable. This one expression was interpolated straight into the script. `github.action_path` is set by the runner, so this is not exploitable today. The rule is about the shape rather than this particular value, and the shape is what makes the habit reliable: a file with one exception teaches a reader that interpolation is sometimes acceptable here, and the next value added may not be runner-controlled. Both sites now go through `ACTION_PATH`. Verified: `scripts/validate_module.sh` OK (10 contract tests, pin check), actionlint 1.7.12 clean across the repository, and zizmor 1.26.1 `--persona=pedantic` reports no findings on either file. --- .github/actions/contract/action.yml | 8 +++++++- .github/actions/lifecycle/action.yml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/actions/contract/action.yml b/.github/actions/contract/action.yml index f447fba..71e26a2 100644 --- a/.github/actions/contract/action.yml +++ b/.github/actions/contract/action.yml @@ -33,13 +33,19 @@ runs: TARGET: ${{ inputs.target }} OUTPUT: ${{ inputs.output }} AT: ${{ inputs.at }} + # Passed through the environment like every other value here. + # A ${{ }} expression interpolated straight into the script is the + # shape actions/code-injection flags, and this file already avoids + # it everywhere else; the runner sets this one, but the rule is + # about the shape, and one exception is what makes a habit unreliable. + ACTION_PATH: ${{ github.action_path }} run: | set -euo pipefail valid_path() { [[ "$1" =~ ^[A-Za-z0-9._/-]+$ && "$1" != /* && "$1" != *..* ]] } valid_path "$PLAN" - root="$(cd -- "${{ github.action_path }}/../../.." && pwd)" + root="$(cd -- "$ACTION_PATH/../../.." && pwd)" case "$COMMAND" in seal) valid_path "$OUTPUT" diff --git a/.github/actions/lifecycle/action.yml b/.github/actions/lifecycle/action.yml index 91d2f2e..d1c154f 100644 --- a/.github/actions/lifecycle/action.yml +++ b/.github/actions/lifecycle/action.yml @@ -33,6 +33,12 @@ runs: APPROVAL: ${{ inputs.approval }} STATE_OUTPUT: ${{ inputs.state_output }} EVIDENCE_OUTPUT: ${{ inputs.evidence_output }} + # Passed through the environment like every other value here. + # A ${{ }} expression interpolated straight into the script is the + # shape actions/code-injection flags, and this file already avoids + # it everywhere else; the runner sets this one, but the rule is + # about the shape, and one exception is what makes a habit unreliable. + ACTION_PATH: ${{ github.action_path }} run: | set -euo pipefail valid_path() { @@ -43,7 +49,7 @@ runs: valid_path "$STATE_OUTPUT" valid_path "$EVIDENCE_OUTPUT" [[ "$OPERATION" =~ ^(apply|verify|resume|rollback)$ ]] - root="$(cd -- "${{ github.action_path }}/../../.." && pwd)" + root="$(cd -- "$ACTION_PATH/../../.." && pwd)" python3 "$root/scripts/cd_contract.py" validate-plan "$PLAN" python3 "$root/scripts/cd_contract.py" validate-state "$PLAN" "$STATE" adapter_args=("$OPERATION" --plan "$PLAN" --state "$STATE" --state-output "$STATE_OUTPUT" --evidence-output "$EVIDENCE_OUTPUT")