For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/security/code_security/iac_security/iac_rules/cicd-github-run-block-injection.md.
A documentation index is available at /llms.txt.
Run steps in GitHub Actions must not interpolate or execute GitHub event fields that can be controlled by external users, because untrusted event data such as PR/issue/discussion titles and bodies, comments, branch names, and commit metadata can contain shell metacharacters or crafted payloads that lead to command injection, arbitrary code execution on runners, or misuse of repository secrets. This risk is amplified for privileged triggers such as pull_request_target and some workflow_run scenarios. For the pull_request trigger, these vulnerable fields are much more significant when the change comes from a fork. Inspect the run property for direct references to GitHub context attributes such as github.event.pull_request.*, github.event.issue.*, github.event.comment.*, github.event.discussion.*, github.event.workflow_run.*, github.head_ref, and github.*.authors.*. Flag any step where the run string contains these patterns. To remediate, avoid shell-interpolating untrusted event data; instead, validate or sanitize inputs, use repository secrets or explicitly whitelisted values, or pass data through actions that perform strict parsing and validation before executing commands. This rule also flags env. usage within the run block.
Secure example that avoids using untrusted event fields:
jobs:build:runs-on:ubuntu-lateststeps:- name:Safe runrun:echo "Build triggered for repository ${{ github.repository }}"
Compliant Code Examples
name:check-go-coverageon:pull_request_target:branches:[master]jobs:coverage:name:Check Go coverageruns-on:ubuntu-lateststeps:- name:Checkout Sourceuses:actions/checkout@v4with:fetch-depth:0- name:Set up Go 1.22.xuses:actions/setup-go@v5with:go-version:1.22.x- name:Run test metrics scriptid:testcovrun:| make test-coverage-report | tee test-results
echo "coverage=$(cat test-results | grep "Total coverage: " test-results | cut -d ":" -f 2 | bc)" >> $GITHUB_ENV- name:Checks if Go coverage is at least 80%if:env.coverage < 80run:| echo "Go coverage is lower than 80%: ${{ coverage }}%"
exit 1
name:Safe composite actiondescription:A composite action that uses inputs through environment variables to avoid shell injectioninputs:slack-message:description:The message to sendrequired:trueruns:using:compositesteps:- name:Send message safelyshell:bashenv:SLACK_MESSAGE:${{ inputs.slack-message }}run:| echo "$SLACK_MESSAGE"
name:Safe composite action without inputsdescription:A composite action whose run block does not interpolate untrusted dataruns:using:compositesteps:- name:Show repositoryshell:bashrun:| echo "Build triggered for ${{ github.repository }}"
Non-Compliant Code Examples
name:Web Page To Markdownon:issues:types:[opened]jobs:WebPageToMarkdown:runs-on:ubuntu-lateststeps:- name:Does the issue need to be converted to markdownrun:| if [ "${{ github.event.issue.body }}" ]; then
if [[ "${{ github.event.issue.title }}" =~ ^\[Auto\]* ]]; then
:
else
echo "This issue does not need to generate a markdown file." 1>&2
exit 1;
fi;
else
echo "The description of the issue is empty." 1>&2
exit 1;
fi;shell:bash- name:Checkoutuses:actions/checkout@v4with:ref:${{ github.head_ref }}- name:Crawl pages and generate Markdown filesuses:freeCodeCamp-China/article-webpage-to-markdown-action@v0.1.8with:newsLink:'${{ github.event.issue.body }}'markDownFilePath:'./chinese/articles/'githubToken:${{ github.token }}- name:Git Auto Commituses:stefanzweifel/git-auto-commit-action@v4.9.2with:commit_message:'${{ github.event.issue.title }}'file_pattern:chinese/articles/*.mdcommit_user_name:PageToMarkdown Botcommit_user_email:PageToMarkdown-bot@freeCodeCamp.org
name:Array Trigger Format Teston:[pull_request, push]jobs:test_array_trigger:runs-on:ubuntu-lateststeps:- name:Process PR with array format triggerrun:| echo "PR Title: ${{ github.event.pull_request.title }}"
echo "Branch: ${{ github.event.pull_request.head.ref }}"