---
title: Untrusted issue, PR or comment text reached a shell in GitHub Actions: find vulnerable workflows, check whether it ran, rotate, fix | ctxsec
url: https://ctxsec.com/playbooks/github-actions-untrusted-text-injection-response
---

[← Playbooks](/playbooks)

# Untrusted issue, PR or comment text reached a shell in GitHub Actions: find vulnerable workflows, check whether it ran, rotate, fix

For when a campaign like the one Radware reported on Oct 29 (83 items across 61 repos on Sept 1, payload calling 54.205.16.142:8443) touched your repos, or you just want to close the hole. Anyone who can open an issue can try this; it needs no write access, and the item can be closed within minutes and still have run.

For: AppSec / platform, DevOps / CI owners, SOC, IR lead

[1. Find vulnerable workflows](#s1)[2. Check whether it ran](#s2)[3. Rotate and review](#s3)[4. Fix and harden](#s4)

1.

Step 1 of 4

__

### Find vulnerable workflows

The bug is a workflow that expands event text inside a run: block.

   - Grep .github/workflows across the org for ${{ github.event.issue.title / .body, pull_request.title / .body / .head_ref, comment.body, review.body, discussion.title / .body used inside run:
   - Prioritize workflows on issues, issue_comment, pull_request_target, discussion and workflow_run triggers, and any that also use secrets or have write permissions
   - Run an Actions linter (zizmor, actionlint) in CI so new cases fail the build
   - List AI review or triage bots that read issue and PR text, and note which tokens they hold

2.

Step 2 of 4

__

### Check whether it ran

A payload in an issue proves an attempt; the run log proves execution.

   - Search issues, PRs and comments (raw Markdown, including HTML comments) since Sept 1, 2026 for 54.205.16.142, :8443/c/, $(curl and env|base64
   - In logs of the matching runs, look for the expanded command line and 'warning: command substitution: ignored null byte in input' on the injected line
   - Check runner egress (self-hosted runner firewall or proxy logs) for connections to 54.205.16.142:8443
   - Note the triggering account; Radware saw established accounts that were likely compromised

3.

Step 3 of 4

__

### Rotate and review

Assume everything the job could read was sent.

   - Rotate every secret available to that job, plus GITHUB_TOKEN-derived access if the job had write permissions (revoke PATs, deploy keys, cloud and registry credentials)
   - Review the org audit log after the run for pushes, tag or release changes, new deploy keys, new workflows and changed branch protections
   - If releases or packages were published after the run, verify them against a known-good build

4.

Step 4 of 4

__

### Fix and harden

Make event text data, not code.

   - Move event values into env: and reference "$VAR" in the script; never eval it
   - Set top-level permissions: contents: read and grant more per job only where needed
   - Keep secrets out of jobs triggered by issues and comments; split privileged work into a separate workflow that runs on trusted triggers
   - Give AI bots that read untrusted text no write tokens or secrets, or isolate them in a job without credentials

Original content by ctxsec. Printable checklist: use your browser's print view.
