Conversation
|
This comment ensures that the correct Slack channel is notified after the team/project label See this comment for details. |
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
General approach:
Set the value of DEFAULT_BUILD_EXCLUDES as an environment variable using the env: block in the workflow step, and reference it in the shell script using shell variable syntax ($DEFAULT_BUILD_EXCLUDES), not via ${{ ... }} interpolation. This prevents code injection via workflow-level interpolation and utilizes the shell's built-in variable substitution.
Detailed fix:
- In the step with
id: compute_hash, move the assignment of${{ env.DEFAULT_BUILD_EXCLUDES }}out of the shell script and into the step’senv:section:- Add
DEFAULT_BUILD_EXCLUDES: ${{ env.DEFAULT_BUILD_EXCLUDES }}under theenv:key.
- Add
- In the shell script, use
EXCLUDES="$DEFAULT_BUILD_EXCLUDES"instead of referencing the variable with${{ ... }}. - No changes to imports or method definitions are needed; this is a straightforward YAML modification and does not alter the workflow's logic.
Files/lines to change:
.github/workflows/docker.yml:- Add
env:to the- name: Compute hash and check if image existsstep (IDcompute_hash) with a line to setDEFAULT_BUILD_EXCLUDESfrom${{ env.DEFAULT_BUILD_EXCLUDES }}. - Change the line
EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}"toEXCLUDES="$DEFAULT_BUILD_EXCLUDES".
- Add
| @@ -260,10 +260,12 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| DEFAULT_BUILD_EXCLUDES: ${{ env.DEFAULT_BUILD_EXCLUDES }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| EXCLUDES="$DEFAULT_BUILD_EXCLUDES" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| fi |
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the potential code injection flaw, one should avoid using ${{ inputs.build-excludes }} directly inside the script block. Instead, pass the input value into an environment variable using the env: block of the step, and reference it using shell-native variable expansion ($BUILD_EXCLUDES). Specifically, in the step running the shell script (id: compute_hash), add an env entry: BUILD_EXCLUDES: ${{ inputs.build-excludes }}. Then, throughout the shell script, replace ${{ inputs.build-excludes }} with $BUILD_EXCLUDES. The same should be done for other workflow inputs being used in the shell script, if they are also user-controlled and interpolated directly.
Changes needed:
- In the step with
id: compute_hash, add to the env section:BUILD_EXCLUDES: ${{ inputs.build-excludes }}(or, create the env block if not present). - Replace every instance of
${{ inputs.build-excludes }}in the run script of that step with$BUILD_EXCLUDES.
No additional dependencies or imports are needed.
| @@ -260,12 +260,14 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| BUILD_EXCLUDES: ${{ inputs.build-excludes }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| if [ -n "$BUILD_EXCLUDES" ]; then | ||
| EXCLUDES+=",$BUILD_EXCLUDES" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then |
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the issue, assign the potentially untrusted input (${{ inputs.build-excludes }}) to an environment variable using the env: key in the GitHub Actions workflow step, rather than interpolating it directly in the run: script. Then, inside the shell script, reference the variable using bash's native $BUILD_EXCLUDES instead of ${{ ... }}. This approach prevents GitHub Actions' expression evaluation from inadvertently exposing the shell to code injection risks, as shell variable expansion does not enable command substitution from workflow input.
Specifically, modify the "Compute hash and check if image exists" step (lines 262–317 in the provided snippet):
- Update the step to add an
env:section, setting something likeBUILD_EXCLUDES: ${{ inputs.build-excludes }}. - Change line
if [ -n "${{ inputs.build-excludes }}" ]; thento use[ -n "$BUILD_EXCLUDES" ] - And where the value is appended (
EXCLUDES+=",${{ inputs.build-excludes }}"), switch toEXCLUDES+=",${BUILD_EXCLUDES}".
No new methods or imports are needed; this is pure YAML and shell quoting discipline.
| @@ -260,12 +260,14 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| BUILD_EXCLUDES: ${{ inputs.build-excludes }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| if [ -n "$BUILD_EXCLUDES" ]; then | ||
| EXCLUDES+=",${BUILD_EXCLUDES}" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then | ||
| @@ -313,7 +311,6 @@ | ||
| # Print for debugging | ||
| echo "IMAGE=${IMAGE}" | ||
| echo "EXISTS=${EXISTS}" | ||
|
|
||
| - name: Print results | ||
| run: | | ||
| echo "Computed tag: ${{ env.image }}" |
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
General fix:
The best way to mitigate this sort of code injection in GitHub Actions shell scripts is to place the untrusted expression (${{ inputs.tag }}) into an intermediate environment variable via the env: block and then only reference it in the shell script using the native variable syntax ($TAG). This ensures that the untrusted input cannot break out of its variable assignment, as GitHub Actions handles safe quoting for environment variables automatically.
Detailed steps:
- Find where
${{ inputs.tag }}is present in the shell script in therun:block (lines 271, 273, 274, 292). - At the step level, define a new environment variable, such as
TAG_INPUT: ${{ inputs.tag }}. - In the shell script, reference the value as
$TAG_INPUTrather than interpolating directly with${{ inputs.tag }}. - Where the script assigns
TAG="${{ inputs.tag }}", instead assignTAG="$TAG_INPUT". - Likewise, update lines where
IMAGEand similar variables were composed with${{ inputs.tag }}to use$TAG_INPUTor$TAGas appropriate. - Do not reference
${{ inputs.tag }}directly in shell code.
Imports/Definitions needed:
No imports necessary. No new packages are needed.
| @@ -260,6 +260,8 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| TAG_INPUT: ${{ inputs.tag }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| @@ -268,10 +270,10 @@ | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then | ||
| echo "🔖 Tag '${{ inputs.tag }}' provided — skipping hash computation." | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${{ inputs.tag }}" | ||
| TAG="${{ inputs.tag }}" | ||
| if [ -n "$TAG_INPUT" ]; then | ||
| echo "🔖 Tag '$TAG_INPUT' provided — skipping hash computation." | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:$TAG_INPUT" | ||
| TAG="$TAG_INPUT" | ||
| EXISTS="false" # Assume not built yet — can still be checked later if desired | ||
| else | ||
| # Enable extended globbing and recursive globs (**) |
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then | ||
| echo "🔖 Tag '${{ inputs.tag }}' provided — skipping hash computation." |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix this code injection risk, do not interpolate ${{ inputs.tag }} directly in the shell script. Instead, assign it as an environment variable, and then refer to it in the script via the shell-native $TAG syntax.
Specifically:
- In the affected step (
Compute hash and check if image exists), add anenv:section to passinputs.taginto the script as an environment variable (e.g.,TAG_INPUT: ${{ inputs.tag }}), or, if you want to preserve the original variable name, asTAG: ${{ inputs.tag }}. - In the script, refer to it using
$TAG(not${{ inputs.tag }}). - Apply the same pattern for other input variables if you use user-supplied input elsewhere in the shell code.
This approach ensures that user data is not implicitly interpreted by the shell, thus preventing code injection.
| @@ -260,6 +260,8 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| TAG: ${{ inputs.tag }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| @@ -268,10 +270,10 @@ | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then | ||
| echo "🔖 Tag '${{ inputs.tag }}' provided — skipping hash computation." | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${{ inputs.tag }}" | ||
| TAG="${{ inputs.tag }}" | ||
| if [ -n "$TAG" ]; then | ||
| echo "🔖 Tag '$TAG' provided — skipping hash computation." | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:$TAG" | ||
| TAG="$TAG" | ||
| EXISTS="false" # Assume not built yet — can still be checked later if desired | ||
| else | ||
| # Enable extended globbing and recursive globs (**) |
| # Compute deterministic content-based hash | ||
| TAG=$("${FIND_CMD[@]}" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) | ||
|
|
||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${TAG}" |
Check warning
Code scanning / CodeQL
Code injection Medium
| # Compute deterministic content-based hash | ||
| TAG=$("${FIND_CMD[@]}" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) | ||
|
|
||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${TAG}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The safest and most robust fix is to avoid injecting untrusted input with ${{ ... }} syntax inside any shell commands, as this can enable code injection.
Instead, use environment variables for all untrusted inputs:
- In the YAML step, place the untrusted input value into an environment variable via the
env:key. - Inside the shell script, use shell native syntax (
$REPOSITORY) for variable expansion, not${{ env.REPOSITORY }}. - Update line 292 in the workflow, replacing
${{ env.REPOSITORY }}with$REPOSITORY.
To implement:
- In
.github/workflows/docker.yml, edit line 292 so that the shell assignment toIMAGEuses$REPOSITORYinstead of${{ env.REPOSITORY }}. - No new imports, just edit inside the shell script block.
| @@ -289,7 +289,7 @@ | ||
| # Compute deterministic content-based hash | ||
| TAG=$("${FIND_CMD[@]}" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) | ||
|
|
||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${TAG}" | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${REPOSITORY}/${{ inputs.image }}:${TAG}" | ||
|
|
||
| # Check if image exists in registry | ||
| if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then |
| # Compute deterministic content-based hash | ||
| TAG=$("${FIND_CMD[@]}" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) | ||
|
|
||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${TAG}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix this code injection vulnerability, the workflow should avoid injecting untrusted input directly into shell commands or variables using the ${{ ... }} expression. Instead, set the value to an environment variable in the env: section, and expand that environment variable using shell-native syntax ("$IMAGE" rather than "${{ inputs.image }}").
In detail:
- Set each external/untrusted input (specifically,
registry,project,image, andtag) to environment variables in theenv:block of the corresponding shell step. - Use the environment variable references in shell (
$IMAGE,$REGISTRY,$PROJECT,$TAG) rather than the${{ ... }}expressions within the run script. - Refactor lines where their values are currently being interpolated using
${{ ... }}to use these environment variables. - This change should occur for all interpolations of those inputs within the script (not just line 292).
- No imports are needed—this is pure GitHub Actions YAML/shell.
| @@ -260,18 +260,24 @@ | ||
|
|
||
| - name: Compute hash and check if image exists | ||
| id: compute_hash | ||
| env: | ||
| REGISTRY: ${{ inputs.registry }} | ||
| PROJECT: ${{ inputs.project }} | ||
| IMAGE: ${{ inputs.image }} | ||
| TAG_INPUT: ${{ inputs.tag }} | ||
| BUILD_EXCLUDES: ${{ inputs.build-excludes }} | ||
| run: | | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| EXCLUDES="${{ env.DEFAULT_BUILD_EXCLUDES }}" | ||
| if [ -n "${{ inputs.build-excludes }}" ]; then | ||
| EXCLUDES+=",${{ inputs.build-excludes }}" | ||
| if [ -n "$BUILD_EXCLUDES" ]; then | ||
| EXCLUDES+=",${BUILD_EXCLUDES}" | ||
| fi | ||
|
|
||
| if [ -n "${{ inputs.tag }}" ]; then | ||
| echo "🔖 Tag '${{ inputs.tag }}' provided — skipping hash computation." | ||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${{ inputs.tag }}" | ||
| TAG="${{ inputs.tag }}" | ||
| if [ -n "$TAG_INPUT" ]; then | ||
| echo "🔖 Tag '$TAG_INPUT' provided — skipping hash computation." | ||
| IMAGE_PATH="$REGISTRY/$PROJECT/${{ env.REPOSITORY }}/$IMAGE:$TAG_INPUT" | ||
| TAG="$TAG_INPUT" | ||
| EXISTS="false" # Assume not built yet — can still be checked later if desired | ||
| else | ||
| # Enable extended globbing and recursive globs (**) | ||
| @@ -289,29 +289,29 @@ | ||
| # Compute deterministic content-based hash | ||
| TAG=$("${FIND_CMD[@]}" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) | ||
|
|
||
| IMAGE="${{ inputs.registry }}/${{ inputs.project }}/${{ env.REPOSITORY }}/${{ inputs.image }}:${TAG}" | ||
| IMAGE_PATH="$REGISTRY/$PROJECT/${{ env.REPOSITORY }}/$IMAGE:$TAG" | ||
|
|
||
| # Check if image exists in registry | ||
| if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then | ||
| echo "✅ Image $IMAGE already exists - skipping build" | ||
| if docker manifest inspect "$IMAGE_PATH" >/dev/null 2>&1; then | ||
| echo "✅ Image $IMAGE_PATH already exists - skipping build" | ||
| EXISTS="true" | ||
| else | ||
| echo "🚀 Image $IMAGE not found — proceed to build" | ||
| echo "🚀 Image $IMAGE_PATH not found — proceed to build" | ||
| EXISTS="false" | ||
| fi | ||
| fi | ||
|
|
||
| # Export values for GitHub Actions | ||
| { | ||
| echo "image=${IMAGE}" | ||
| echo "image=${IMAGE_PATH}" | ||
| echo "image_exists=${EXISTS}" | ||
| echo "tag=${TAG}" | ||
| } >> "$GITHUB_ENV" | ||
|
|
||
| echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" | ||
| echo "image=${IMAGE_PATH}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # Print for debugging | ||
| echo "IMAGE=${IMAGE}" | ||
| echo "IMAGE=${IMAGE_PATH}" | ||
| echo "EXISTS=${EXISTS}" | ||
|
|
||
| - name: Print results |
|
|
||
| - name: Print results | ||
| run: | | ||
| echo "Computed tag: ${{ env.image }}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the potential code injection vulnerability, we should assign the value to an environment variable using the env: property of the step, and then reference that variable in the shell using the proper shell syntax ("$image"), not via GitHub Actions expression syntax. In this case, for the 'Print results' step, we will move ${{ env.image }} and ${{ env.image_exists }} into environment variables (e.g., IMAGE and IMAGE_EXISTS) using the env: key, and inside the shell script, reference them as "$IMAGE" and "$IMAGE_EXISTS". This prevents shell injection even if those values contain special characters.
Only the 'Print results' step (lines 317–321) needs updates: add an env: mapping, and change the script to use shell variables instead of ${{ env. ... }}.
| @@ -315,9 +315,12 @@ | ||
| echo "EXISTS=${EXISTS}" | ||
|
|
||
| - name: Print results | ||
| env: | ||
| IMAGE: ${{ env.image }} | ||
| IMAGE_EXISTS: ${{ env.image_exists }} | ||
| run: | | ||
| echo "Computed tag: ${{ env.image }}" | ||
| echo "Image exists: ${{ env.image_exists }}" | ||
| echo "Computed tag: $IMAGE" | ||
| echo "Image exists: $IMAGE_EXISTS" | ||
|
|
||
| - name: Extract metadata (tags, labels) for Docker | ||
| id: meta |
| - name: Print results | ||
| run: | | ||
| echo "Computed tag: ${{ env.image }}" | ||
| echo "Image exists: ${{ env.image_exists }}" |
Check warning
Code scanning / CodeQL
Code injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the code injection risk, the variable ${{ env.image_exists }} should not be interpolated directly using expression syntax in the run: block. Instead, pass the value as an environment variable and then reference it via shell-native variable expansion (i.e., $image_exists). Specifically, in the .github/workflows/docker.yml file, modify the relevant step ("Print results") to set an environment variable, then use the shell's $image_exists syntax when echoing the value. No behavioral change is introduced; the fix simply ensures that any injected meta-characters cannot be interpreted by the shell.
| @@ -315,9 +315,11 @@ | ||
| echo "EXISTS=${EXISTS}" | ||
|
|
||
| - name: Print results | ||
| env: | ||
| IMAGE_EXISTS: ${{ env.image_exists }} | ||
| run: | | ||
| echo "Computed tag: ${{ env.image }}" | ||
| echo "Image exists: ${{ env.image_exists }}" | ||
| echo "Image exists: $IMAGE_EXISTS" | ||
|
|
||
| - name: Extract metadata (tags, labels) for Docker | ||
| id: meta |
https://remerge.atlassian.net/browse/CORE-1345