Your CI pipeline runs a trusted Action. It builds your project, runs your tests, and quietly forwards your GITHUB_TOKEN to an attacker-controlled server — all in the same workflow step. By the time the build completes with a green checkmark, the token is already in someone else’s hands.
This is Shai-Hulud.
TL;DR
- Shai-Hulud is a TypeScript/Bun credential harvesting framework built for GitHub Actions supply chain attacks
- Developed by TeamPCP, open-sourced on May 13, 2026 and spotted by security researchers shortly after publication
- Collects GitHub tokens (
ghtoken,ghs_,ghs_jwt) from the CI environment and exfiltrates to git-tanstack.com- Falls back to GitHub API as a secondary exfiltration channel if C2 is unreachable
- Includes Russian-language detection to skip execution in Russian-locale systems — classic crimeware behavior
- Supports obfuscated builds via
bun run build:obfto evade static analysis- Has been specifically observed targeting opensearch-js repositories with
release-drafter.ymlworkflow files- IoC to block immediately:
git-tanstack.com
Table of Contents
- What Is Shai-Hulud
- Attack Chain
- Module Breakdown
- Evasion Techniques
- Indicators of Compromise
- Detection
- Mitigations
- Sources
What Is Shai-Hulud
Named after the colossal sandworm in Frank Herbert’s Dune, Shai-Hulud is a CI/CD credential harvesting framework — a tool designed to run silently inside GitHub Actions environments and steal everything of value: tokens, secrets, and environment variables.
On May 13, 2026, a threat actor group calling themselves TeamPCP open-sourced the tool on GitHub under the handle PedroTortoriello/Shai-Hulud-Open-Source. The repository description reads: “Here We Go Again — Let the Carnage Continue. A Gift From TeamPCP.” The tool surfaced through the security community on the same day — researchers independently spotting the repository shortly after publication.
The codebase is written in TypeScript and runs on the Bun runtime — an unusual combination for malware, but effective. The package is named voicefromtheouterworld in package.json, masking its true purpose if package metadata is used for triage.
The project includes a standard build and an obfuscated build:
bun installbun run build # clean buildbun run build:obf # obfuscated build for deploymentThis is not a proof-of-concept or a toy. The code is functional, modular, and built with operational evasion in mind.
Attack Chain
The typical deployment scenario for Shai-Hulud is a supply chain compromise: the attacker inserts the payload into a GitHub Action that victim repositories depend on. When the Action runs in a target CI pipeline, Shai-Hulud executes with access to the runner environment.
Compromised GitHub Action (dependency) │ ▼Victim's GitHub Actions runner │ ├─ FileSystemService ──► scan filesystem for credentials ├─ ShellService ──► execute shell commands, capture output └─ GitHubRunner ──► extract GitHub runner context │ ▼Token extraction: ghtoken / ghs_ / ghs_jwt patterns │ ▼Token validation via GitHub API │ ├─ Primary: HTTPS → git-tanstack.com (C2) └─ Fallback: GitHub API (dead drop exfiltration) │ ▼GitHubActionsService instantiated with stolen token→ Attacker gains full repository accessThe use of git-tanstack.com as the C2 domain is deliberate — the domain resembles legitimate git tooling infrastructure. HTTPS traffic to it blends into normal CI network activity and is unlikely to be blocked by default.
If the primary C2 is unreachable, the tool falls back to the GitHub API itself as an exfiltration channel, making network-level blocking alone insufficient.
Module Breakdown
Shai-Hulud follows a clean modular architecture under src/:
| Module | Role |
|---|---|
collector/ | Gathers data from filesystem, shell, and GitHub runner context |
dispatcher/ | Orchestrates collection and routing of harvested data |
sender/domain/ | Transmits data to git-tanstack.com |
sender/github/ | GitHub API-based fallback exfiltration |
github_utils/fetcher.ts | GitHub API calls |
github_utils/tokenCheck.ts | Validates stolen tokens before exfiltration |
mutator/ | Runtime payload mutation and string obfuscation |
providers/ | Pluggable backends for different exfiltration targets |
assets/ | Packed static resources bundled into the binary |
The scramble() function inside index.ts obfuscates sensitive strings at runtime — including "GITHUB_ACTIONS" and "SIGINT" — to prevent static string matching from identifying the payload.
A lock mechanism prevents multiple simultaneous instances from running, avoiding noisy behavior that might trigger alerting on high process counts.
Evasion Techniques
Shai-Hulud uses several techniques to avoid detection:
Russian locale check — The tool inspects system locale settings and skips execution if the environment is configured for Russian. This is a classic crimeware pattern used to avoid targeting systems in regions where the threat actor operates — providing legal cover.
Obfuscated build — bun run build:obf produces an obfuscated binary. Combined with Bun’s single-binary output format, the payload becomes difficult to analyze statically.
Silent error handling — Errors are caught and suppressed throughout the codebase. No stack traces, no failed exit codes — the workflow step completes normally.
Disguised package name — The npm package is named voicefromtheouterworld, not shai-hulud. Tools that triage packages by name will not find it.
HTTPS C2 traffic — All exfiltration uses HTTPS to git-tanstack.com. The domain name is designed to look like developer tooling. Firewall rules targeting known malicious IPs will not catch it.
Legitimate-looking cover — The README describes a “README updater” workflow — a believable CI task that masks what the tool is actually doing.
Targeted scope — Observed targeting of opensearch-js repositories with release-drafter.yml suggests this is not a spray-and-pray campaign. Specific targeting reduces exposure and increases operational longevity.
Indicators of Compromise
Network
| Indicator | Type | Context |
|---|---|---|
git-tanstack.com | Domain | Primary C2 / exfiltration endpoint |
Code Patterns (for repository scanning)
| Pattern | Context |
|---|---|
ghtoken | Token search string in collector |
ghs_old | Legacy GitHub token pattern |
ghs_jwt | GitHub JWT token pattern |
voicefromtheouterworld | Disguised package name |
bun run build:obf | Obfuscated build in CI |
git-tanstack | C2 reference in source |
Behavioral
| Indicator | Context |
|---|---|
| Bun runtime executing in GitHub Actions | Uncommon — worth flagging |
release-drafter.yml workflow in opensearch-js scope | Known targeted workflow |
| CI job exiting clean with no artifacts but outbound HTTPS | Exfiltration pattern |
Detection
GitHub Actions Audit Log (via GitHub API)
Review token usage anomalies — a GITHUB_TOKEN used outside the expected workflow steps or calling unexpected API endpoints is a strong signal.
gh api /orgs/{org}/audit-log \ --paginate \ --jq '.[] | select(.action | startswith("git.")) | {actor, action, repo, created_at}'Workflow File Scanning
# Scan local repositories for known IoCsgrep -r "git-tanstack" .github/grep -r "voicefromtheouterworld" .github/grep -r "bun run build:obf" .github/Sigma Rule — Suspicious Outbound from CI Runner
title: Suspicious Outbound HTTPS from GitHub Actions Runner to git-tanstack.comid: a3f92c11-84b1-4e2d-9f33-c74a1e8d5b20status: experimentaldescription: Detects network connections to the known Shai-Hulud C2 domainauthor: Hive Securitydate: 2026-05-13logsource: category: proxy product: github_actionsdetection: selection: dst_host|contains: 'git-tanstack.com' condition: selectiontags: - attack.exfiltration - attack.t1567falsepositives: - None expectedlevel: criticalWazuh Rule
<rule id="100501" level="15"> <if_group>web_log</if_group> <url>git-tanstack.com</url> <description>Shai-Hulud C2: outbound connection to known exfiltration domain</description> <mitre> <id>T1567</id> </mitre></rule>Sentinel KQL — GitHub Audit Log
GitHubAuditLog| where TimeGenerated > ago(24h)| where Action startswith "git."| where AdditionalFields contains "git-tanstack"| project TimeGenerated, Actor, Action, Repository, AdditionalFields| order by TimeGenerated descMitigations
| Control | Implementation |
|---|---|
| Pin GitHub Actions to commit SHA | Use uses: action/name@sha256:abc123 instead of @v1 — prevents silent updates from injecting payloads |
Restrict GITHUB_TOKEN permissions | Set permissions: read-only in workflow YAML; grant write only where required |
Block git-tanstack.com | Add to DNS blocklist and egress firewall rules immediately |
| Enable GitHub Actions network controls | Use github.com/enterprise egress allowlisting if on GHES |
| Audit third-party Actions | Review all uses: dependencies; prefer actions in your own org or well-audited orgs |
| Monitor token usage | Enable GitHub audit log streaming to SIEM; alert on tokens used outside expected workflows |
| Dependency scanning in CI | Use tools like actionlint, zizmor, or StepSecurity’s Harden-Runner to detect suspicious workflow behavior |
| Avoid Bun in CI unless required | Flag unexpected Bun installations in GitHub Actions as anomalous |
Sources
- Shai-Hulud-Open-Source GitHub Repository — TeamPCP, published 2026-05-13
- MITRE ATT&CK T1567 — Exfiltration Over Web Service
- MITRE ATT&CK T1195.001 — Supply Chain Compromise: Compromise Software Dependencies
- GitHub Actions security hardening
- tj-actions supply chain incident (2025) — comparable attack vector