Workflow writes untrusted content to $GITHUB_ENV
Control: Workflow must not write untrusted content to $GITHUB_ENV· Config key: workflowMustNotWriteUntrustedContentToGitHubEnv
📋 What is this?
A workflow routes PR-author-controlled content into $GITHUB_ENV or $GITHUB_PATH — directly (echo "KEY=${{ github.event.* }}" >> $GITHUB_ENV), through an env:-bound shell variable, or through a heredoc/redirect whose body dereferences the value.
⚠️ Impact
Writing attacker-controlled content to $GITHUB_ENV creates an environment variable for every subsequent step in the job. A title containing newlines (foo\nMALICIOUS_PATH=...) can inject *multiple* env vars at once, including overriding $PATH.
🔧 How to fix
Binding the value through env: stops command injection (ISSUE-207) but not this: a newline still opens a second $GITHUB_ENV line and any value poisons $GITHUB_PATH. Base64-encode the untrusted value itself before writing it (so no newline survives) or wrap it in toJSON. If it's only needed within one step, keep it in env: and don't write to the sticky file at all.
# .github/workflows/triage.yml — ❌ Untrusted into $GITHUB_ENVon: pull_request_targetjobs: triage: runs-on: ubuntu-latest steps: - run: echo "TITLE=${{ github.event.pull_request.title }}" >> $GITHUB_ENV# .github/workflows/triage.yml — ✅ Pre-bind + base64on: pull_request_targetjobs: triage: runs-on: ubuntu-latest steps: - env: PR_TITLE: ${{ github.event.pull_request.title }} run: | encoded=$(printf '%s' "$PR_TITLE" | base64 -w0) echo "TITLE_B64=$encoded" >> $GITHUB_ENV💡 Tips
- Use the same trick for
$GITHUB_OUTPUTand$GITHUB_PATH. - If you only need the value within one step, env: is enough — don't write to $GITHUB_ENV at all.
- A fixed heredoc delimiter (
<<EOF) doesn't help — the body still lands in $GITHUB_ENV verbatim; randomise the delimiter or base64-encode the value. - base64 must wrap the untrusted value itself; a base64 elsewhere on the line (e.g.
$(date | base64)) does not neutralise a raw$VAR.
⚙️ Configuration
This control is configured in .plumber.yaml under the github section:
github:
controls:
workflowMustNotWriteUntrustedContentToGitHubEnv:
enabled: trueSee the CLI documentation for the full configuration reference.