Insecure Example
Interpolating untrusted input inside the
Never build shell scripts by concatenating or expanding variables directly in the script body.
run block lets attackers inject arbitrary commands.Never build shell scripts by concatenating or expanding variables directly in the script body.
Secure Approach
By passing untrusted input via theenv block, the value is provided to the shell at execution time rather than expanded when the workflow is generated.
Defining
The shell will see it only as data.
issue_title as an environment variable prevents any injected payload from being interpreted as part of the script.The shell will see it only as data.
Insecure vs. Secure Comparison
| Aspect | Insecure Workflow | Secure Workflow |
|---|---|---|
| Expansion point | Inline script (run block) | Environment variable (env block) |
| Vulnerability | Shell interprets injected characters as commands | Shell treats the entire value as a string |
| Example assignment | issue_title="{{ github.event.issue.title }}" | issue_title: '${{ github.event.issue.title }}' |
Demonstration of Attack Mitigation
Simulate an issue title containing a malicious payload:Workflow Logs
curl request is executed—only the intended logic runs.
HTTP Dump Confirmation
Inspecting the HTTP dump shows only the initial probe requests, confirming no secrets were exfiltrated:Further Reading
References
- GitHub Actions Documentation: https://docs.github.com/actions
- OWASP Cheat Sheet: Command Injection Prevention: https://cheatsheetseries.owasp.org/cheatsheets/Command_Injection_Prevention_Cheat_Sheet.html