ci: bind docker/pypi workflow inputs via env before shell
What changed, and why it matters
This commit hardens three GitHub Actions workflow files by moving user-controlled inputs into environment variables before they are used in shell scripts. Previously, values like platform lists, Docker Hub owner names, and PyPI distribution locations were inserted directly into shell commands. If someone with workflow trigger access supplied specially crafted input, they could potentially inject shell commands. The change follows GitHub's recommended practice of binding inputs to environment variables first, which reduces that risk.
Review and merge as a security hardening improvement. Ensure all other workflows in the repository follow the same pattern of binding inputs to env variables before shell use. Consider whether inputs.version and github.ref_type in pypi-publish.yml still need similar env binding for consistency.
Security signals we found
GitHub Actions script-injection hardening
Workflow inputs moved from inline expression interpolation to env variables
Defensive CI/CD security fix
No changelog entry (Changelog-None)
Evidence from the diff
The patch remediates a script-injection class issue in GitHub Actions workflows. In docker-build.yml, docker-publish.yml, and pypi-publish.yml, workflow inputs and matrix values that were previously interpolated directly into run: shell scripts (e.g., ${{ inputs.platforms-to-build }}, ${{ inputs.dh-repository-owner }}, ${{ inputs.version }}, ${{ matrix.tag_suffix }}, ${{ inputs.dist-location }}) are now assigned to env: variables and referenced via shell variables. This prevents direct expression expansion inside the shell, mitigating command injection via malicious input values. The change is defensive and does not by itself demonstrate an active exploit.
Changed components
.github/workflows/docker-build.yml.github/workflows/docker-publish.yml.github/workflows/pypi-publish.ymlInspect captured patch +22 / −9
### .github/workflows/docker-build.yml
@@ -23,8 +23,10 @@ jobs:
platforms: ${{ steps.plan.outputs.platforms }}
steps:
- id: plan
+ env:
+ PLATFORMS_TO_BUILD: ${{ inputs.platforms-to-build }}
run: |
- IFS=',' read -ra ARR <<< "${{ inputs.platforms-to-build }}"
+ IFS=',' read -ra ARR <<< "$PLATFORMS_TO_BUILD"
JSON=$(printf '%s\n' "${ARR[@]}" | jq -R . | jq -sc .)
echo "platforms=$JSON" >> "$GITHUB_OUTPUT"
### .github/workflows/docker-publish.yml
@@ -43,25 +43,34 @@ jobs:
merge-multiple: false
- name: Set up values
+ env:
+ DH_REPOSITORY_OWNER: ${{ inputs.dh-repository-owner }}
+ PUSH_LATEST: ${{ inputs.push-latest }}
+ VERSION: ${{ inputs.version }}
+ REF_TYPE: ${{ github.ref_type }}
run: |
DIGEST_REFS=""
for f in /tmp/digests/*/digest.txt; do
D=$(cat "$f")
- DIGEST_REFS="$DIGEST_REFS ${{ inputs.dh-repository-owner }}/lightningd@${D}"
+ DIGEST_REFS="$DIGEST_REFS ${DH_REPOSITORY_OWNER}/lightningd@${D}"
done
echo "DIGEST_REFS=$DIGEST_REFS" >> $GITHUB_ENV
- if [[ "${{ inputs.push-latest }}" == "true" ]] ||
- ([[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ inputs.version }}" =~ rc ]]); then
+ if [[ "$PUSH_LATEST" == "true" ]] ||
+ ([[ "$REF_TYPE" == "tag" ]] && [[ ! "$VERSION" =~ rc ]]); then
echo "PUSHLATEST=true" >> $GITHUB_ENV
else
echo "PUSHLATEST=false" >> $GITHUB_ENV
fi
- name: Create and push real tag(s)
+ env:
+ DH_REPOSITORY_OWNER: ${{ inputs.dh-repository-owner }}
+ VERSION: ${{ inputs.version }}
+ TAG_SUFFIX: ${{ matrix.tag_suffix }}
run: |
- TAG_ARGS=(-t "${{ inputs.dh-repository-owner }}/lightningd:${{ inputs.version }}${{ matrix.tag_suffix }}")
+ TAG_ARGS=(-t "${DH_REPOSITORY_OWNER}/lightningd:${VERSION}${TAG_SUFFIX}")
if [[ "$PUSHLATEST" == "true" ]]; then
- TAG_ARGS+=(-t "${{ inputs.dh-repository-owner }}/lightningd:latest${{ matrix.tag_suffix }}")
+ TAG_ARGS+=(-t "${DH_REPOSITORY_OWNER}/lightningd:latest${TAG_SUFFIX}")
fi
docker buildx imagetools create "${TAG_ARGS[@]}" $DIGEST_REFS
### .github/workflows/pypi-publish.yml
@@ -30,9 +30,11 @@ jobs:
- name: Determine PyPI distribution location
id: set-values
- run: |
- if [[ "${{ inputs.dist-location }}" != "" ]]; then
- DISTLOCATION="${{ inputs.dist-location }}"
+ env:
+ DIST_LOCATION: ${{ inputs.dist-location }}
+ run: |
+ if [[ -n "$DIST_LOCATION" ]]; then
+ DISTLOCATION="$DIST_LOCATION"
elif [[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ inputs.version }}" =~ rc ]]; then
DISTLOCATION="prod"
elseWhy this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.