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/supply-chain.md
Supply Chain: Third-Party Actions
Overview
GitHub Actions workflows depend on third-party actions referenced by uses:. If these actions are not pinned to immutable references (full commit SHAs), attackers can compromise them via tag mutation, account takeover, or fork-and-replace attacks.
Policy: pin third-party actions and reusable workflows to a full 40-character commit SHA. Do not require SHA pins for first-party GitHub actions (actions/*, github/*) on version tags, or for same-repo / vendored actions.
What Counts As Third-Party
| Source | Classification | Pinning finding? |
|---|---|---|
actions/* (GitHub official) | First-party | No — version tags are fine |
github/* (GitHub org) | First-party | No — version tags are fine |
Same-repo / vendored (./.github/actions/...) | Not third-party supply chain | No as supply-chain pinning (still review in pwn-request context) |
| Org-owned / internal first-party actions when reviewing that org's repos | First-party for that org | No unless the action is external to the org's trust boundary |
| External orgs (aws-actions, docker, tj-actions, community, unknown) | Third-party | Yes — pin to full SHA when privilege makes it relevant |
When org ownership is unclear, treat non-actions/* / non-github/* / non-local refs as third-party.
Pinning: Tags vs. SHAs
Reportable: Unpinned Third-Party Tags
# REPORT when third-party and the job is privileged enough (see severity)
- uses: some-org/some-action@v1 # Tag — mutable third-party
- uses: tj-actions/changed-files@v44
- uses: docker/build-push-action@v6
- uses: some-org/some-action@main # Branch — mutableTags are mutable Git references. The maintainer (or attacker with write access) can delete and recreate a tag pointing to a different commit. When the tag is updated, every workflow using that tag runs the new code.
Safe: Third-Party SHA Pinning
# SAFE for third-party: commit SHA is immutable
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2SHAs are immutable — once a commit exists, its SHA cannot change. Pin third-party actions to the full 40-character SHA and add a comment with the version for readability.
Do Not Report: First-Party Version Tags
# NOT a supply-chain pinning finding
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/upload-artifact@v4
- uses: github/codeql-action/analyze@v3
- uses: ./.github/actions/local-buildFirst-party actions/* and github/* on version tags are not findings by themselves. Same-repo or vendored actions are not third-party supply-chain findings (they can still be unsafe if loaded from a PR-controlled checkout — that is a pwn-request / trust-crossing issue, not pinning).
Attack Vectors
Tag Mutation Attack
Attacker compromises a popular third-party action's repository (phishing, leaked credentials, insider)
Deletes the
v1tagCreates a new
v1tag pointing to a malicious commitEvery workflow using
@v1now runs the attacker's code
This is not theoretical — CVE-2025-30066 (tj-actions/changed-files) and related incidents showed tag rewrites can leak secrets at scale.
Account Takeover / Org Compromise
If a third-party action author's GitHub account is compromised:
All actions under that account can be backdoored
Version tags can be silently updated
Users won't notice unless they're pinned to SHAs
Fork-and-Replace
Original action author deletes their repository
Attacker creates a fork with the same
owner/reponameExisting workflows that reference
owner/repo@tagnow pull from the attacker's fork
Actions That curl | bash at Runtime
Some actions download and execute external scripts at runtime:
# Action's action.yml — RISKY even when SHA-pinned
runs:
using: composite
steps:
- run: curl -sSfL https://example.com/install.sh | bash
shell: bashEven if you pin the action to a SHA, the external URL can change. The action itself is immutable, but its runtime dependencies are not. Report this for third-party actions in privileged jobs; do not use it as a reason to demand SHA pins on first-party GitHub actions.
Detection Patterns
# Find third-party action references (exclude first-party + local)
grep -rn "uses:" .github/workflows/ \
| grep -v "#" \
| grep -v "uses: \\.\\/" \
| grep -v "actions/" \
| grep -v "github/"
# Among third-party refs, find unpinned tags/branches (not full SHA)
grep -rn "uses:" .github/workflows/ \
| grep -v "#" \
| grep -v "uses: \\.\\/" \
| grep -v "actions/" \
| grep -v "github/" \
| grep -v "@[0-9a-f]\\{40\\}"
# Find third-party actions pinned to branch names
grep -rn "uses:" .github/workflows/ \
| grep -v "actions/\\|github/\\|\\./" \
| grep -E "@(main|master|develop|latest)"Do not treat every non-SHA uses: as a finding. Filter to third-party first, then assess job privilege.
When To Report
Report mutable third-party actions only when job privilege makes compromise security-relevant.
| Shape | Severity |
|---|---|
| Mutable third-party ref in package publishing, release signing, protected-branch push, production deploy, or token-minting job | High / Critical (unknown org + pull_request_target / secrets → Critical) |
Mutable third-party ref with secrets, OIDC, or non-trivial write-scoped GITHUB_TOKEN | High or Medium depending on blast radius |
| Pinned third-party action that downloads and executes mutable remote scripts in a privileged job | Medium, or High when the downloaded payload runs inside the privileged step |
| Mutable third-party ref in public read-only CI with no secrets and no write scopes | No finding unless adjacent to another traced workflow risk |
Unpinned first-party actions/* / github/* version tags | No finding |
| Local / vendored action pinning | No finding as supply chain (review pwn-request separately) |
Risk Assessment by Third-Party Source
Use this only after the ref is classified third-party and the job is privileged enough to report:
| Source | Risk | Action |
|---|---|---|
| Major orgs (aws-actions, google-github-actions, docker) | Medium | Pin to SHA |
| Popular community actions (1k+ stars) | Medium | Pin to SHA, review source |
| Less-known actions (under 100 stars) | High | Pin to SHA, review source carefully, consider vendoring |
| Unknown / single-maintainer | Critical | Vendor locally or replace with inline run: |
The Fix: SHA Pin Third-Party Actions
steps:
# First-party: version tags are fine — do not flag
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
# Third-party: pin to SHA, comment with version for readability
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2Automated Pinning
Tools that can pin and update third-party action SHAs:
Dependabot — GitHub native, updates action SHAs
Renovate — Can pin and update actions
StepSecurity Secure Workflows — Can pin actions to SHAs (configure to match third-party-only policy if you do not want first-party pins)
Vendoring Critical Actions
For high-security workflows, vendor the third-party action locally:
# Instead of: uses: some-org/critical-action@v1
# Copy the action into your repo:
- uses: ./.github/actions/critical-actionSeverity Guidelines
| Pattern | Severity | Rationale |
|---|---|---|
Unpinned third-party action from unknown org used in pull_request_target | Critical | Attacker could backdoor the action AND access secrets |
| Unpinned third-party action from known org in sensitive/privileged workflow | High | Tag mutation risk with secret exposure |
| Unpinned third-party action with limited privilege but real write/secret surface | Medium | Real supply-chain risk, bounded blast radius |
| Third-party action that curls external scripts at runtime in a privileged job | High | Even SHA-pinned actions can be compromised via external deps |
Unpinned first-party actions/* / github/* | Do not report | Outside pinning policy |
Local action (./.github/actions/) unpinned | Do not report as pinning | Controlled by repo; only risky in pwn-request context |
Exploitation Scenario Template
ATTACK: Supply Chain via [unpinned third-party action / tag mutation / curl|bash]
ENTRY: Attacker compromises [third-party action repo / account / external URL]
PAYLOAD: Malicious code in [action.yml / downloaded script]
TRIGGER: Workflow [file:line] uses third-party [action@tag] without SHA pin
EXECUTION: Modified action runs with workflow permissions
IMPACT: [RCE with workflow permissions, secret theft, 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