name: Mini Shai-Hulud Runner.Worker Memory Secret Extraction Analytic
category: 'Credential Access'
threatname: 'Unsecured Credentials: CI/CD Object Credentials'
functionality: 'Endpoint Management Systems'
description: |
Detects the secret extraction grep pattern used by the Mini Shai-Hulud npm worm (TeamPCP)
to harvest all GitHub Actions secrets from Runner.Worker process memory. The worm executes
a Python script via stdin that reads /proc/{Runner.Worker PID}/mem across all readable
memory pages, then pipes output through grep targeting the runner's internal masked secret
representation: {"value":"...","isSecret":true}
The full pipeline executed from within the Bun payload process is:
sudo python3 | tr -d '\0' | grep -aoE '"[^"]+":{"value":"[^"]*","isSecret":true}' | sort -u
The isSecret string in a grep CommandLine during any package install context has no
legitimate use case and is a near-zero-FP indicator of this specific attack technique.
DEPLOYMENT SCOPE: Developer workstations and self-hosted CI runners only.
GitHub managed runners are hosted infrastructure outside your control — Sysmon For Linux
cannot be deployed there and no endpoint telemetry is available from those machines.
Self-hosted runners are the higher-priority deployment target because they hold npm
publish tokens and cloud credentials that the worm actively seeks. This rule fires at
the moment the memory scrape executes — the earliest possible detection point in the
credential theft phase.
Sysmon For Linux EVID 1 is the required telemetry source.
reference:
- https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
- https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack
- https://www.aikido.dev/blog/mini-shai-hulud-is-back-tanstack-compromised
- https://github.com/fluffybunnies-h4x/FT-Linux-Sysmon-Config
labels:
- attack.credential_access
- attack.t1552
- attack.t1552.007
- attack.t1059.006
- Mini_Shai_Hulud
- TeamPCP
- Supply_Chain
- TanStack
logsource:
category: process_creation
product: linux
detection:
selection_grep_secret_pattern:
Image|endswith:
- '/grep'
CommandLine|contains:
- 'isSecret'
selection_runner_worker_target:
CommandLine|contains:
- 'Runner.Worker'
- 'isSecret":true'
condition: selection_grep_secret_pattern or selection_runner_worker_target
criticality: Critical
saveasthreat: false
violation_summary:
grouping_attribute: 'accountname'
level2_attribute: 'devicehostname'
level2_metadata_attributes:
TECHNICAL DETAILS:
DEPLOYMENT SCOPE
----------------
Target systems: Developer workstations, self-hosted CI runners
Do NOT deploy: GitHub managed runners (no endpoint visibility — not org-owned)
Priority target: Self-hosted CI runners first. These machines hold npm publish
tokens and cloud credentials; compromise here enables the worm
to re-publish infected packages under your organization's name.
Developer workstations second — credential haul is significant
but propagation risk is lower without publish tokens.
DETECTION MECHANICS
-------------------
The worm invokes the following pipeline via execSync() from within bun.exe:
sudo python3 | tr -d '\0' \
| grep -aoE '"[^"]+":{"value":"[^"]*","isSecret":true}' \
| sort -u
The grep process will carry 'isSecret' in its CommandLine regardless of whether
the full regex is visible. The parent of grep in this pipeline is the shell (sh)
spawned by Bun, but the grep CommandLine is the detection anchor — it is
unique to this technique and has no legitimate equivalent in any npm workflow.
The Python script (Payload 5) reads:
/proc/{Runner.Worker PID}/maps — enumerates readable memory regions
/proc/{Runner.Worker PID}/mem — reads raw memory pages
This extracts every secret configured in the workflow including masked values
that are never written to disk and never appear in log output.
Full process tree observed during StepSecurity runtime analysis:
npm install (PID 2332)
└─ node npm-cli.js install (PID 2343)
└─ sh -c "bun run opensearch_init.js" (PID 2364)
└─ bun.exe opensearch_init.js (PID 2365)
└─ sudo python3 | tr | grep | sort (PID 2386-2391)
Telemetry note: grep and sort are short-lived child processes in a shell pipeline.
Confirm that your Sysmon For Linux configuration captures process creation events
for short-lived processes. The FT-Linux-Sysmon-Config reference config captures
these correctly via EVID 1.
False Positives:
- Essentially none. No legitimate security tool or CI debug script constructs
a grep pattern targeting the GitHub Actions internal secret JSON format.
- Theoretical FP: a developer writing a custom runner debug script who happens
to know the Runner.Worker internal memory format. Treat as negligible.
Policy building walkthrough can be found in this previous post:
Sysmon For Linux is CRITICAL for this detection to work
Here is the github repo I co-maintain to help security professionals who haven’t installed or worked with Sysmon For Linux get it up and running:
