Intelligence
criticalVulnerabilityActive

GitHub Actions Shell Injection via Unsanitized Issue Metadata in Workflow Templates

GitHub Actions workflows that directly interpolate untrusted issue fields (title, body, labels) into shell `run` blocks using template expressions are vulnerable to command injection. This PoC demonstrates that unauthenticated attackers can trigger arbitrary code execution and exfiltrate secrets by crafting malicious issue titles.

S
Sebastion

Affected

Zen-Ai-Pentest/zenclaw-discord-integration

Vulnerability Description

This vulnerability is a shell command injection in GitHub Actions workflows caused by unsafe template variable resolution. The root cause is embedding GitHub Actions context variables (e.g., ${{ github.event.issue.title }}) directly into bash script blocks without proper escaping or sanitization. The GitHub Actions template engine resolves these expressions at workflow compilation time, substituting the raw untrusted value as literal bash code before the runner executes the script. Because the substitution occurs within double-quoted strings, bash interprets subshell syntax like $(command) and backticks `...`. An attacker with no repository privileges can trigger the issues: [opened] event by creating a public issue with a crafted title, causing arbitrary code execution in the workflow runner context—including access to all secrets available to that workflow.

Proof-of-Concept Significance

This PoC is significant because it demonstrates a reliable, low-barrier attack vector against GitHub Actions infrastructure. The trigger requires only the ability to create an issue (often public-by-default), meaning external, unauthenticated users can exploit it. The PoC reliably proves that workflow secrets (e.g., DISCORD_WEBHOOK_URL, API keys, deployment credentials) can be exfiltrated by injecting subshell commands into the issue title. Since GitHub Actions templates are resolved at compilation time—not runtime—traditional shell escaping techniques fail. This makes the vulnerability particularly insidious: developers may incorrectly assume that GitHub Actions context variables are "safe" without explicit sanitization.

Detection Guidance

Workflow-Level Indicators:

  • Audit .github/workflows/ YAML files for patterns: run: | or run: > blocks that directly reference ${{ github.event.issue.* }}, ${{ github.event.pull_request.* }}, or other user-controllable context variables without shell quoting (e.g., ${{ toJSON(...) }} or environment variable indirection).
  • Flag workflows where context variables appear in variable assignments, command substitutions, or within conditional expressions without ::set-output or ::set-env commands (which have additional protections).

Runtime Indicators (in runner logs):

  • Unexpected command execution or subshell invocations in workflow logs (check for $() or backtick evaluation in Prepare Notification or similar steps).
  • Environment variable exfiltration attempts (e.g., curl, wget, or file reads targeting env or .env files).
  • Anomalous HTTP POST requests to external domains (e.g., webhook URL changes or unauthorized webhook calls).

SAST/Linting:

  • Use GitHub Actions linters (e.g., github-actions-linter) to flag direct context variable interpolation in run blocks.
  • Implement custom rules in YAML parsers to detect ${{ github.event.issue. patterns within shell contexts.

Mitigation Steps

Immediate Patch (Recommended):

  1. Move untrusted context variables into GitHub Actions environment variables using env: blocks, which are passed safely and do not undergo template expansion within their values:
    - name: Prepare Notification
      env:
        ISSUE_TITLE: ${{ github.event.issue.title }}
      run: |
        # ISSUE_TITLE is now a shell environment variable, not injected at template-expansion time
        DESCRIPTION="$ISSUE_TITLE"
  2. Use toJSON() wrapper for complex objects to enforce strict escaping:
    DESCRIPTION: ${{ toJSON(github.event.issue.title) }}
  3. Implement explicit input validation in the workflow or downstream code; use shell parameter expansion modifiers to strip dangerous characters if injection patterns are detected.

Workarounds (if patching is delayed):

  • Disable the issues: [opened] trigger and restrict workflows to push or pull_request events on trusted branches only.
  • Require issue creation/editing to be restricted to organization members (repository settings).
  • Add a manual approval step before the vulnerable workflow runs.

Long-term Security:

  • Enforce a code review policy for all GitHub Actions workflows, specifically checking for context variable interpolation in run blocks.
  • Use GitHub Advanced Security (code scanning) to flag these patterns automatically.
  • Rotate any secrets (Discord webhook URLs, API keys) that were exposed prior to patching.

Risk Assessment

Likelihood of Exploitation in the Wild: High. The attack requires minimal effort (crafting an issue title), no authentication, and succeeds reliably across any repository using similar workflow patterns. Public GitHub repositories with automated workflows are high-value targets. Automated scanning tools can easily enumerate vulnerable workflows across GitHub (since workflows are often public).

Threat Actor Interest: Very High. This vulnerability enables:

  • Supply chain attacks: Injecting malicious code into CI/CD pipelines of downstream users or projects.
  • Secret exfiltration: Stealing API keys, deployment tokens, and webhook URLs for lateral movement or further compromise.
  • Supply chain poisoning: Modifying build outputs or deployments during CI/CD.

Given the maturity of GitHub Actions as a CI/CD platform and its widespread adoption, this class of vulnerability is particularly attractive to organized threat actors targeting software development infrastructure.