No. A pull request title, branch name, body or commit message is written by the contributor, so it is untrusted input. If you place it directly inside a shell step with an expression, the text can become part of the command. Pass it through an intermediate environment variable, or use an action that takes it as an argument.
Definition: script injection
In GitHub Actions, an expression written with dollar and double braces is replaced with its value before the shell script runs. If the value contains shell syntax, the shell executes it. That is script injection. GitHub's secure use guidance describes it and lists the contexts that deserve suspicion.
Why external contributors make it worse
Anyone can open a pull request from a fork and choose its title. If a workflow on a privileged trigger echoes the title inside a run step, the contributor chooses what that step runs. The risk grows when the workflow has secrets or a write token, as privileged triggers can.
Fields to treat as untrusted
- Pull request title, body and head branch name
- Issue titles and bodies, and comment text
- Commit messages and author names
- Head repository name and labels set by others
- Anything read from an artifact produced by another workflow
The unsafe pattern and the safe one
Unsafe, because the title is expanded into the script text:
- run: echo "Title is ${{ github.event.pull_request.title }}"
Safe, because the title lands in a variable and the shell treats it as data:
- env:
TITLE: ${{ github.event.pull_request.title }}
run: echo "Title is $TITLE"
GitHub names this as the preferred approach for inline scripts. The other recommended approach is a JavaScript action that receives the value as an argument, because the value never becomes a shell script.
Quote the variable in the shell, and never pass it to eval, to a command substitution, or to a tool that interprets it as options.
A review routine
- Search workflow files for expressions that read github.event fields inside run blocks.
- For each hit, ask whether a stranger can control the value.
- Move it to an env entry and quote its use.
- Check scripts the workflow calls, not just the workflow file.
- Run a workflow linter or code scanning for Actions workflows. GitHub notes CodeQL can scan and detect potentially vulnerable workflows when default setup has Actions scanning enabled.
A related lesson
Public incident write ups have shown pull request title injection in real repositories. Read our explainer on the nx s1ngularity pull request title injection for how that played out, and use this post as the prevention checklist.
Try it yourself
Click through it at your own pace, or open it full screen.
Look at how a static scan reports a risky data flow with the file and line.
Where Safeguard fits
Safeguard gates run on pull requests and its dependency scanning checks what a change brings in. A free scan is a way to see current findings.
Quick check
Is a branch name safe because Git limits characters?
No. Branch names allow many shell relevant characters. Treat them as untrusted.
Does an env variable fully prevent injection?
It prevents the value from becoming script text, but you must still quote it and avoid eval style use.
Sources
Last reviewed: 19 October 2026.