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-github-env.md.
A documentation index is available at /llms.txt.
Writing to the special GitHub Actions environment files GITHUB_ENV or GITHUB_PATH from workflow steps that handle untrusted input can inject environment variables or alter PATH, enabling attackers to escalate privileges or achieve arbitrary code execution.
This rule inspects GitHub Actions workflow steps with a run: body in workflows that use dangerous triggers such as pull_request_target or workflow_run, and flags occurrences that write to those files. It detects > and >> shell redirections, pipeline-to-tee patterns, PowerShell Out-File/Add-Content/Set-Content/Tee-Object, and Windows cmd echo/write patterns targeting $GITHUB_ENV, $GITHUB_PATH, ${env:GITHUB_ENV}, %GITHUB_ENV%, and similar variants. The audit ignores trivially static echo statements with only literal text but will flag commands that include variable expansion, command substitution, multiple arguments, or unknown commands that may introduce attacker-controlled data.
Secure alternative using step outputs instead of writing to GITHUB_ENV:
name:GitHub Env Test - Negative Cases# Safe: No dangerous triggerson:push:branches:[main]jobs:safe-trigger:runs-on:ubuntu-lateststeps:# Even with GITHUB_ENV writes, this is safe because of the trigger- name:Safe with push triggerrun:echo $foo >> $GITHUB_ENV---name:Safe Patterns with Dangerous Triggeron:pull_request_targetjobs:safe-static-echo:runs-on:ubuntu-lateststeps:# Safe: completely static strings- name:Static string literalrun:echo "FOO=bar" >> $GITHUB_ENV- name:Static without quotesrun:echo completely-static >> $GITHUB_ENVno-env-write:runs-on:ubuntu-lateststeps:- name:Regular echorun:echo "Hello World"- name:Write to different filerun:echo $foo >> $OTHER_FILE- name:Comment onlyrun:echo $foo >> $OTHER_ENV# not $GITHUB_ENVwrong-variables:runs-on:ubuntu-lateststeps:- name:Similar but not exact variable namerun:echo $foo >> $GITHUB- name:Another similar namerun:echo $foo | tee $GITHUB_ENVXactions-only:runs-on:ubuntu-lateststeps:- uses:actions/checkout@v4- uses:actions/setup-node@v4with:node-version:18---# Composite action: write to GITHUB_PATH with only local bash variables. Even# though `$HOME` is variable expansion, no attacker-influenced GitHub Actions# context flows in, so the composite branch must not flag this.name:Benign composite actiondescription:Composite action whose write to GITHUB_PATH only uses local bash varsruns:using:compositesteps:- name:Add local bin to PATHshell:bashrun:echo "$HOME/bin" >> $GITHUB_PATH---# Composite action: step.env carries an unused untrusted input but the actual# GITHUB_ENV write only appends a constant. The taint never flows into the# env-file write, so the composite branch must not flag this.name:Composite with unused taintdescription:Untrusted env entry is unused; the GITHUB_ENV write is constantinputs:message:description:Untrusted but unusedrequired:trueruns:using:compositesteps:- name:Constant write with unused taintshell:bashenv:MSG:${{ inputs.message }}run:echo "$HOME/bin" >> $GITHUB_PATH
Non-Compliant Code Examples
name:GitHub Env Test - Positive Caseson:pull_request_target:types:[opened, synchronize]jobs:bash-redirect-unsafe:runs-on:ubuntu-lateststeps:- name:Unsafe echo with variablerun:echo $foo >> $GITHUB_ENV- name:Unsafe echo with multiple variablesrun:echo $foo $bar >> $GITHUB_ENV- name:Unsafe echo with command substitutionrun:echo FOO=$(bar) >> $GITHUB_ENV- name:Unsafe with bracesrun:echo $foo >> ${GITHUB_ENV}- name:Unsafe with quotesrun:echo $foo >> "$GITHUB_ENV"bash-pipeline:runs-on:ubuntu-lateststeps:- name:Unsafe tee patternrun:something | tee $GITHUB_ENV- name:Unsafe tee with quotesrun:something | tee "$GITHUB_ENV"bash-path:runs-on:ubuntu-lateststeps:- name:Unsafe GITHUB_PATH writerun:echo $foo >> $GITHUB_PATHpowershell-unsafe:runs-on:windows-lateststeps:- name:Out-File patternshell:pwshrun:| echo "CUDA_PATH=$env:CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append- name:Add-Content patternshell:pwshrun:| Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_VERSION=$releaseVersion"- name:Set-Content patternshell:pwshrun:| Set-Content -Path $env:GITHUB_ENV -Value "tag=$tag"- name:Tee-Object patternshell:pwshrun:| echo "BRANCH=${{ env.BRANCH_NAME }}" | Tee-Object -Append -FilePath "${env:GITHUB_ENV}"- name:PowerShell redirectshell:pwshrun:| echo "UV_CACHE_DIR=$UV_CACHE_DIR" >> $env:GITHUB_ENVcmd-unsafe:runs-on:windows-lateststeps:- name:CMD redirect patternshell:cmdrun:echo LIBRARY=%LIBRARY% >> %GITHUB_ENV%
name:Composite action writing to GITHUB_ENVdescription:Composite action that writes attacker-influenced content to GITHUB_ENVinputs:message:description:Untrusted inputrequired:trueruns:using:compositesteps:- name:Unsafe redirectshell:bashenv:MSG:${{ inputs.message }}run:echo $MSG >> $GITHUB_ENV
name:Composite multi-arg redirect to GITHUB_ENVdescription:Composite step writes more than one arg to GITHUB_ENV in a single redirectinputs:message:description:Untrusted inputrequired:trueruns:using:compositesteps:- name:Multi-arg unsafe redirectshell:bashenv:MSG:${{ inputs.message }}run:echo "FOO=$MSG" "BAR=baz" >> $GITHUB_ENV
1
2
rulesets:- CICD / GitHub # Rules to enforce / GitHub.
Request a personalized demo
Get Started with Datadog
Ask AI
AI-generated responses may be inaccurate. Verify important info.