# Hackers Target 61 GitHub Repositories With Command Injection Attacks to Steal CI/CD Secrets

> Radware documented a campaign of 83 malicious GitHub issues, pull requests and comments, published on 2026-09-01 against 61 public repositories, that abuse GitHub Actions workflows which insert user-controlled text into shell scripts. The Bash $() payloads dump environment variables, Base64-encode them and attempt an HTTP POST to 54.205.16.142:8443; command execution was evidenced in two workflow runs, but secret theft and repository compromise were not confirmed.

- **Published:** 2026-11-02T05:05:13Z
- **Last reviewed:** 2026-11-02T05:05:13Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-5030
- **Card image:** https://intel.threadlinqs.com/og/threat/TL-2026-5030.png
- **ID:** TL-2026-5030
- **Severity:** HIGH
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Detections:** 9 (1 shown free below) · **IOCs:** 14 (1 shown free below)

## Description

On 2026-09-01 an apparently single actor published 83 verified malicious items (59 issues and 24 pull requests) across 61 public GitHub repositories using 74 distinct accounts. Radware noted that many of the accounts had development histories that looked legitimate; secondary reporting suggests some may have been compromised, which Radware did not establish. Targets included google/langextract, aquasecurity/trivy, brave/brave-browser, mlflow, ToolJet/ToolJet, PX4/PX4-Autopilot, Snouzy/workout-cool, agno-agi/agno, Homebrew/homebrew-cask and github/docs. 77 of the 83 items were posted in about 43 minutes (reported as 11:26:51 to 12:10:00 UTC) and the remaining 6 about 2 minutes later, roughly 1.8 malicious posts per minute in the first wave. The 16 most popular targeted repositories hold roughly 460,600 GitHub stars in total.

The attack relies on shell command injection through untrusted GitHub content processed by GitHub Actions. The payload is a Bash command substitution $() placed in an issue or pull request title (31 items), body (17 items) or comment (35 items). According to Radware's analysis as reported by secondary sources, the commands were hidden inside HTML comments so they do not appear on the rendered page, while workflows still ingest the raw text. Workflows that place this text directly into shell source, notably title-checking and notification workflows, expand the substitution and run the attacker's command inside the runner; the triggered workflow starts within about a second of the event, so a vulnerable workflow executes the payload almost immediately.

The observed command runs env to collect the runner environment (which can include CI/CD secrets and tokens), removes newlines, Base64-encodes the result and uses curl to send an HTTP POST to 54.205.16.142 on port 8443. All verified payloads pointed to this destination. The connection is plain HTTP rather than HTTPS, and each attempt carries a unique collection identifier. Radware examined actual workflow run logs and found two prominent cases with direct evidence that the command executed in the automation environment. Radware could not confirm that the attacker gained write permissions, modified repositories, compromised distributed code, or obtained usable credentials. By 2026-10-13, about 42% of the items (35 of 83) were still open.

No CVE, named threat actor or malware family is associated with this campaign. The weakness is insecure workflow design (CWE-77/CWE-78 style injection of untrusted input into shell code). Recommended defenses are to treat all GitHub-sourced text as untrusted, pass it to scripts via environment variables rather than interpolating it into shell source, avoid eval, restrict workflow token permissions and secret exposure, and separate notification jobs from privileged release workflows. Note: the Radware blog could not be retrieved directly (browser verification page), so campaign details come from the Cyber Security News article and three secondary reports that cite the Radware research.

## MITRE ATT&CK

- T1585 Establish Accounts
- T1190 Exploit Public-Facing Application
- T1195.002 Compromise Software Supply Chain
- T1059.004 Unix Shell
- T1027 Obfuscated Files or Information
- T1552 Unsecured Credentials
- T1005 Data from Local System
- T1119 Automated Collection
- T1132.001 Standard Encoding
- T1071.001 Web Protocols
- T1048.003 Exfiltration Over Unencrypted Non-C2 Protocol

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**GitHub Actions Runner Env Dump → Base64 → curl Chain (CI/CD Secret Exfiltration)** (`TL-2026-5030-SPL-001`)

Detects the injected GitHub Actions command-substitution payload from the TL-2026-5030 campaign (Radware: 83 malicious issues/PRs/comments across 61 repos) executing on a self-hosted runner: within one minute a runner step script spawns env/printenv, base64 and curl. The payload dumps runner secrets with env, Base64-encodes them and POSTs them to 54.205.16.142:8443. Flags the chain by behaviour and marks hits whose command line references the known exfil IP/port.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1190, T1195.002, T1059.004, T1552, T1132.001
- **Data sources:** sysmon_for_linux, linux_auditd, microsoft_defender_for_endpoint
- **Severity:** high
- **Confidence:** high

### Splunk SPL

```spl
index=linux sourcetype="sysmon:linux" earliest=-24h EventCode=1
(Image="*/env" OR Image="*/printenv" OR Image="*/base64" OR Image="*/tr" OR Image="*/curl")
(ParentCommandLine="*/_temp/*" OR ParentCommandLine="*/_work/*")
| eval proc=replace(Image,"^.*/","")
| bin _time span=1m
| stats values(proc) as procs values(CommandLine) as cmdlines min(_time) as first_seen by host User _time
| where isnotnull(mvfind(procs,"^(env|printenv)$")) AND isnotnull(mvfind(procs,"^base64$")) AND isnotnull(mvfind(procs,"^curl$"))
| eval cmd_blob=mvjoin(cmdlines," ")
| eval ioc_hit=if(like(cmd_blob,"%54.205.16.142%") OR like(cmd_blob,"%:8443%"),"yes","no")
| convert ctime(first_seen)
| table first_seen host User procs cmdlines ioc_hit
```

### Microsoft KQL

```kql
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName in~ ("env", "printenv", "base64", "tr", "curl")
| where InitiatingProcessCommandLine has_any ("/_temp/", "/_work/")
| summarize Procs=make_set(tolower(FileName)), CmdLines=make_set(ProcessCommandLine, 25), FirstSeen=min(Timestamp) by DeviceName, AccountName, Window=bin(Timestamp, 1m)
| where (set_has_element(Procs, "env") or set_has_element(Procs, "printenv")) and set_has_element(Procs, "base64") and set_has_element(Procs, "curl")
| extend IocHit = tostring(CmdLines) has_any ("54.205.16.142", ":8443")
| project FirstSeen, DeviceName, AccountName, Procs, CmdLines, IocHit
```

### Sigma

```yaml
title: GitHub Actions Runner Step Script Spawns curl POST With Inline Data
id: 7d3f2a91-5c4e-4b86-9a1d-0e6b8f3c2a10
status: experimental
description: Detects curl spawned from a GitHub Actions runner step script posting inline data, as in the TL-2026-5030 command-injection campaign exfiltrating Base64-encoded environment variables.
references:
  - https://www.radware.com/blog/inside-a-github-supply-chain-attack-campaign/
  - https://cybersecuritynews.com/hackers-target-61-github-repositories/
author: AII-Detector — ThreadLinqs Intelligence
date: 2026-11-02
tags:
  - attack.initial-access
  - attack.t1190
  - attack.t1195.002
  - attack.execution
  - attack.t1059.004
  - attack.credential-access
  - attack.t1552
  - attack.command-and-control
  - attack.t1132.001
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentCommandLine|contains:
      - '/_temp/'
      - '/_work/'
  selection_curl:
    Image|endswith: '/curl'
  selection_post:
    CommandLine|contains:
      - ' -d '
      - '--data'
      - '-X POST'
  condition: all of selection_*
falsepositives:
  - Legitimate workflow steps that POST build status or webhooks with curl (allowlist destination hosts)
level: high

```

**Known false positives:**

- Legitimate CI steps that dump env for debugging and curl a known notification/webhook endpoint
- Release workflows posting build metadata to internal artifact services

**Tuning notes:** Applies to self-hosted runners with Sysmon for Linux/auditd telemetry (GitHub-hosted runners are not observable). Adjust the index/sourcetype to your environment, allowlist known runner hosts and approved webhook destinations, and raise priority when ioc_hit=yes. Widen span=1m if step scripts run slowly.

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- GitHub Actions Step curl POST to IP-Literal HTTP Endpoint (Injected Exfil) (locked: unlock with TL Creds)
- Shell Command Line Piping Environment Into base64 or Reading /proc/*/environ (locked: unlock with TL Creds)
- curl HTTP POST to IP-Literal URL from CI Runner (Non-TLS Exfil Pattern) (locked: unlock with TL Creds)
- GitHub Actions Runner Script Spawns base64 Encoder (Env Encoding Stage) (locked: unlock with TL Creds)
- GitHub Actions Runner Script Strips Newlines With tr -d (Payload Encoding Cleanup) (locked: unlock with TL Creds)
- curl Process Connection to [indicator] or Port 8443 (Host-Level Exfil) (locked: unlock with TL Creds)
- CI Runner Secret Staging: env + Newline Strip + base64 Without Network Stage (locked: unlock with TL Creds)
- Network Egress to TL-2026-5030 Exfil Endpoint [indicator]:8443 (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sample indicators (1 of 14)

Defanged, TLP:CLEAR.

- IP address: `54.205.16[.]142`

Full set of 14 indicators unlocks with TL Creds: https://threadlinqs.com/tl-creds

## Sources

- [Hackers Target 61 GitHub Repositories With Command Injection Attacks to Steal CI/CD Secrets](https://cybersecuritynews.com/hackers-target-61-github-repositories/)
- [Radware: Inside a GitHub Supply Chain Attack Campaign](https://www.radware.com/blog/inside-a-github-supply-chain-attack-campaign/)
- [Google's LangExtract Among 61 Repos Targeted in 43 Minutes](https://fourweekmba.com/ai-googles-langextract-among-61-repos-targeted-in-43-minutes/)
- [GitHub bajo ataque: 61 repositorios expuestos a una campaña de cadena de suministro](https://www.diariobitcoin.com/tecnologia/github-bajo-ataque-61-repositorios-expuestos-a-una-campana-de-cadena-de-suministro/)
- [Hidden GitHub comments hit 61 repositories (news digest)](https://freemalta.com/news/digest/global/hidden-github-comments-hit-61-pmxgim)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-5030
