Harden L10n workflows against branch-name script injection#99
Harden L10n workflows against branch-name script injection#99arpitjain099 wants to merge 2 commits into
Conversation
The localization workflows interpolate github.head_ref and
github.base_ref directly into run blocks. Because the Actions runner
substitutes ${{ }} into the script text before bash executes it, a
crafted branch name on a pull request could inject shell commands
(for example in the OLD_BRANCH assignment that feeds git diff).
Pass the branch-ref and other github-context values through step-level
env: variables and reference them as quoted shell variables instead.
Runtime behavior is unchanged; the values are no longer evaluated as
part of the script. This follows GitHub's security-hardening guidance
for avoiding script injection.
Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
Kusari Analysis Results:
No pinned version dependency changes, code issues or exposed secrets detected! Note View full detailed analysis result for more information on the output and the checks that were run.
Found this helpful? Give it a 👍 or 👎 reaction! |
| echo "(DEBUG) github.actor: ${ACTOR}" | ||
| echo "(DEBUG) github.base_ref: ${BASE_REF}" | ||
| echo "(DEBUG) github.event_name: ${EVENT_NAME}" | ||
| echo "(DEBUG) github.event_path: ${EVENT_PATH}" |
There was a problem hiding this comment.
Issue: The run block directly uses ${{ }} template expressions for github.token, github.workflow, github.repository, github.repository_owner, github.run_id, github.run_number, github.sha, and github.workspace. All of these should be assigned to environment variables at the step or job level and referenced via
Recommended Code Changes:
env:
REPOSITORY: ${{ github.repository }}
REPOSITORY_OWNER: ${{ github.repository_owner }}
RUN_ID: ${{ github.run_id }}
RUN_NUMBER: ${{ github.run_number }}
SHA: ${{ github.sha }}
WORKFLOW: ${{ github.workflow }}
WORKSPACE: ${{ github.workspace }}
run: |
echo "(DEBUG) github.repository: ${REPOSITORY}"
echo "(DEBUG) github.repository_owner: ${REPOSITORY_OWNER}"
echo "(DEBUG) github.run_id: ${RUN_ID}"
echo "(DEBUG) github.run_number: ${RUN_NUMBER}"
echo "(DEBUG) github.sha: ${SHA}"
echo "(DEBUG) github.workflow: ${WORKFLOW}"
echo "(DEBUG) github.workspace: ${WORKSPACE}"
# Remove the github.token echo entirely - never log tokens
…step
The 'Show the github context' debug step echoed ${{ github.token }} straight
into the workflow log and still interpolated several github.* values directly
inside the run block. Drop the token echo entirely (a token should never be
written to logs) and pass the remaining context values
(repository, repository_owner, run_id, run_number, sha, workflow, workspace)
through the env block, referenced as shell variables. This finishes the
expression-injection hardening for this step.
Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
|
Good catch from the Kusari scan. I pushed a follow-up commit that finishes hardening the
That keeps every context value out of the shell-parsed command text, so there's no expression-injection surface left in that step. |
|
Kusari PR Analysis rerun based on - e781b80 performed at: 2026-06-02T01:28:03Z - link to updated analysis |
What
The two localization workflows reference branch-ref context values directly inside
run:blocks:check-outdated-content.yaml:${{ github.base_ref }}and${{ github.head_ref }}appear in the bash steps, includingOLD_BRANCH="origin/${{github.base_ref}}", which is then used ingit diff ${OLD_BRANCH}..${LATEST_BRANCH}.post-outdated-content-report.yaml: the debug step echoes${{ github.head_ref }},${{ github.base_ref }}, and the raw${{ github }}context.Why this matters
${{ }}expressions are expanded into the script text by the Actions runner before bash runs, so a value an attacker can influence (a pull-request branch name) is concatenated straight into the command. A branch named something like$(...)can therefore execute arbitrary commands when the workflow runs. This is the script-injection pattern described in GitHub's security hardening guide, and it is what CodeQL'sactions/expression-injectionquery and zizmor flag.The change
Each affected branch-ref value is now passed through a step-level
env:block and referenced as a quoted shell variable ("$HEAD_REF") insiderun:. Environment variables are not re-parsed by the shell, so the untrusted text can no longer alter the script. I also routed the report workflow's context dump throughtoJSON(github)inenv:rather than echoing the raw${{ github }}object.No behavior changes: the same values are logged and the same git refs are compared.