Mini Shai-Hulud's GitHub Actions Pwn-Request → OIDC Token Theft Chain
Background. Mini Shai-Hulud (the TeamPCP self-propagating npm worm) first surfaced in coverage on 2026-05-10 as a SAP CAP-package compromise. The original campaign relied on attacker-published versions of dependency-chain packages catching legitimate downstream consumers; its blast-radius was bounded by which packages opted into the affected dependency graph. The 2026-05-11 second wave ( materially changes the attack pattern — it uses no infostealer of a maintainer's machine, no credential theft from the package owner; instead it abuses a class problem in GitHub Actions that lets attacker-controlled fork code reach into the privileged release workflow of an upstream repository (StepSecurity, 2026-05-11; TanStack post-mortem, 2026-05-12; Wiz, 2026-05-12).
The chain in defender terms.
- Reconnaissance. The operator (
voicproducoes, GitHub account ID 269549300, created 2026-03-19) identifies a target repository whose CI/CD configuration triggers onpull_request_target. That event is the privileged form ofpull_request— it runs in the base repository's context with secrets and write tokens available, not the fork's sandbox. GitHub's docs flag this; many high-volume monorepos still rely on it for fork-aware CI features. Mapped toT1593 Search Open Websites/Domains(the operator surveys public Actions configurations). - Fork-and-rename. The operator forks the target repo (e.g.
TanStack/router) and immediately renames the fork (zblgg/configuration) to evade fork-list discovery — fork-list scans against the upstream do not surface a fork that has been renamed off the original namespace. Mapped toT1583.001 Acquire Infrastructure: Domains-equivalent for source-control identity. - Pwn-Request. The operator submits a PR from the renamed fork. The base repo's
pull_request_targetworkflow executes, but with attacker-controlled code paths reached via subtle changes the human reviewer is unlikely to read (e.g. a modifiedpnpm-lock.yaml, a new dev-dependency, or a CI helper script under.github/). Mapped toT1199 Trusted RelationshipandT1505.003 Web Shell-equivalent for CI execution. The PR does not need to be merged — its mere existence runs the privileged workflow. - Cache poisoning. The privileged workflow run, now executing attacker-influenced code with base-repo secrets, writes a malicious pnpm store into the GitHub Actions cache key for the project's lockfile hash. The cache key is shared with the legitimate release workflow, so the legitimate
pnpm installin the next maintainer-merged release will restore the poisoned store rather than fetch upstream tarballs. Mapped toT1195.002 Supply Chain Compromise: Compromise Software Supply Chain. - Wait for release. Maintainers merge legitimate PRs to
main. The release workflow onmainrestores the poisoned cache, builds the package using the trojanised pnpm store, and reaches the publish step. - OIDC-token theft via
/proc/<pid>/mem. At this point the release runner has been issued a short-lived GitHub Actions OIDC token by GitHub's identity provider. The token sits in the workflow process's memory but is not surfaced as an environment variable to step scripts. The attacker-controlled binary inside the poisoned pnpm store reads/proc/<runner-pid>/memto scrape the token directly out of process memory. Mapped toT1003.007 OS Credential Dumping: Proc Filesystem. - npm token exchange. The harvested OIDC token is exchanged at npm's well-known token-exchange endpoint for a per-package publish token. Because npm trusts the OIDC issuer (GitHub Actions identity), the token-exchange is a legitimate trust-federation operation — no audit signal at the npm side distinguishes it from a normal publish. The worm uses this short-lived publish token to upload poisoned versions of every package the OIDC scope can reach. Mapped to
T1078.004 Cloud AccountsandT1606.002 Forge Web Credentials: SAML Tokens-equivalent for OIDC. - Provenance fraud. Because the poisoned tarball was built inside the legitimate GitHub Actions runner and published via the legitimate OIDC trust path, the npm registry signs the package with a valid SLSA Build Level 3 provenance attestation. The "Publish Packages" step in the maintainer's workflow YAML was bypassed entirely — the publish call came from the worm — but the attestation is cryptographically valid. This is the most significant evolution: SLSA L3 was the assurance many EU procurement frameworks were starting to demand; this campaign demonstrates it is forgeable when an attacker controls any step in the workflow chain that produces the artefact, not just the publish step. The closest MITRE ATT&CK fit is
T1553.002 Subvert Trust Controls: Code Signing— though no current ATT&CK sub-technique precisely maps to SLSA-L3 provenance forgery via OIDC abuse in a CI pipeline; detection-engineering playbooks should be built from the CI-side primitives rather than from a generic code-signing detection rule. - Payload & propagation. Each poisoned package contains a 2.3 MB triple-obfuscated
router_init.jsthat onpostinstallharvests AWS IMDSv2, ECS metadata, HashiCorp Vault tokens,~/.aws, SSH keys, npm tokens, GitHub tokens, Kubernetes service accounts, browser cookie jars and 100+ further credential paths. Exfiltration is dual-channel: the Session Protocol (decentralised, takedown-resistant) with RSA-4096-OAEP + AES-256-GCM, and a GitHub GraphQL dead-drop that commits to attacker-controlled branches (Dune-universe names) authored asclaude@users.noreply.github.com. Persistence is installed in Claude Code's.claude/settings.json, VS Code's.vscode/tasks.json, OS-level LaunchAgents and systemd units. Agh-token-monitordaemon polls the GitHub API every 60 seconds and executesrm -rf ~/if the harvested token is revoked — a dead-man's-switch wiper. - Self-spread. With the harvested npm tokens, the worm publishes further poisoned versions to every package each compromised maintainer can reach, repeating the chain.
What detection looks like. No IOCs in this brief; the behaviour patterns to alert on are the durable signals:
- CI/CD telemetry: any GitHub Actions workflow run triggered by
pull_request_targetthat wrote to the Actions cache and was not initiated by a trusted contributor. The audit-log noise is high; pin the alert to "workflow-run accessedactions/cache/savefrom a job that was reachable via fork". - Runner-process introspection: any step that reads from
/proc/*/memfrom a non-rootprocess on the runner. GitHub-hosted runners do not need to read/proc/<pid>/memfor any legitimate workflow purpose. Self-hosted runners should treat the same heuristic as a high-severity alert (Sysmon-equivalent on the runner OS). - npm publish anomalies: unusual concurrency of publish events for a package family that does not normally release simultaneously (TanStack 42 packages in a 6-minute window is the visible artefact). npm's audit log surfaces this if the org has it enabled.
- Developer-workstation post-install: processes spawned by
npm/pnpm/yarnpostinstallthat read~/.aws,~/.ssh,~/.npmrcor/proc/self/environ(Sysmon EID 1 with parent-image filter on the package-manager binary). - Dead-man's-switch awareness: do not revoke a suspected-compromised GitHub PAT or npm token from the affected developer machine before quarantining that machine. Revocation triggers
rm -rf ~/. Quarantine first; rotate from a clean host.
Hardening — class-level fixes, not per-incident patches.
- Pin every
pull_request_targetworkflow to a SHA-locked version of every action it uses; never@mainor@v1. Forks cannot influence what runs. - Disable cache writes from any workflow that can be reached via a fork PR (
actions/cachewithsave: falsefrompull_request_target). - Use separate workflows for fork-reachable CI (sandboxed, read-only on secrets) and for release (no fork-reachable trigger).
- Audit the OIDC trust chain in your npm / PyPI / GitHub-Container-Registry organisation: scope publish trust to a specific repo and a specific workflow file path, not just the repo.
- For SLSA-attestation reliance: treat L3 as a necessary but not sufficient signal — pair it with a maintainer-verified
npm provenance verifyagainst a published expected workflow-file-path, not just the issuer. The 2026-05-11 campaign shows L3 alone is forgeable. - Sanitise developer endpoints before token revocation (the
rm -rf ~/dead-man's-switch). Treat any pnpm cache restore ornode_modulesdirectory pre-dating the disclosure as suspect.
ATT&CK mapping
9 techniques mapped from the cited reporting · MITRE ATT&CK v19.2
Reconnaissance TA0043
T1593Search Open Websites/Domains
Adversaries may search freely available websites and/or domains for information about victims that can be used during targeting. Information about victims may be available in various online sites, such as social media, new sites, or those hosting information about business operations such as hiring or requested/rewarded contracts.
Resource Development TA0042
T1583.001Acquire Infrastructure: Domains
Adversaries may acquire domains that can be used during targeting. Domain names are the human readable names used to represent one or more IP addresses. They can be purchased or, in some cases, acquired for free.
Initial Access TA0001
T1078.004Valid Accounts: Cloud Accounts
Valid accounts in cloud environments may allow adversaries to perform actions to achieve Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Cloud accounts are those created and configured by an organization for use by users, remote support, services, or for administration of resources within a cloud service provider or SaaS application. Cloud Accounts can exist solely in the cloud; alternatively, they may be hybrid-joined between on-premises systems and the cloud through syncing or federation with other identity sources such as Windows Active Directory.
T1195.002Supply Chain Compromise: Compromise Software Supply Chain
Adversaries may manipulate application software prior to receipt by a final consumer for the purpose of data or system compromise. Supply chain compromise of software can take place in a number of ways, including manipulation of the application source code, manipulation of the update/distribution mechanism for that software, or replacing compiled releases with a modified version.
T1199Trusted Relationship
Adversaries may breach or otherwise leverage organizations who have access to intended victims. Access through trusted third party relationship abuses an existing connection that may not be protected or receives less scrutiny than standard mechanisms of gaining access to a network.
Persistence TA0003
T1078.004Valid Accounts: Cloud Accounts
Valid accounts in cloud environments may allow adversaries to perform actions to achieve Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Cloud accounts are those created and configured by an organization for use by users, remote support, services, or for administration of resources within a cloud service provider or SaaS application. Cloud Accounts can exist solely in the cloud; alternatively, they may be hybrid-joined between on-premises systems and the cloud through syncing or federation with other identity sources such as Windows Active Directory.
T1505.003Server Software Component: Web Shell
Adversaries may backdoor web servers with web shells to establish persistent access to systems. A Web shell is a Web script that is placed on an openly accessible Web server to allow an adversary to access the Web server as a gateway into a network. A Web shell may provide a set of functions to execute or a command-line interface on the system that hosts the Web server.
Privilege Escalation TA0004
T1078.004Valid Accounts: Cloud Accounts
Valid accounts in cloud environments may allow adversaries to perform actions to achieve Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Cloud accounts are those created and configured by an organization for use by users, remote support, services, or for administration of resources within a cloud service provider or SaaS application. Cloud Accounts can exist solely in the cloud; alternatively, they may be hybrid-joined between on-premises systems and the cloud through syncing or federation with other identity sources such as Windows Active Directory.
Stealth TA0005
T1078.004Valid Accounts: Cloud Accounts
Valid accounts in cloud environments may allow adversaries to perform actions to achieve Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Cloud accounts are those created and configured by an organization for use by users, remote support, services, or for administration of resources within a cloud service provider or SaaS application. Cloud Accounts can exist solely in the cloud; alternatively, they may be hybrid-joined between on-premises systems and the cloud through syncing or federation with other identity sources such as Windows Active Directory.
Defense Impairment TA0112
T1553.002Subvert Trust Controls: Code Signing
Adversaries may create, acquire, or steal code signing materials to sign their malware or tools. Code signing provides a level of authenticity on a binary from the developer and a guarantee that the binary has not been tampered with. The certificates used during an operation may be created, acquired, or stolen by the adversary. Unlike Invalid Code Signature, this activity will result in a valid signature.
Credential Access TA0006
T1003.007OS Credential Dumping: Proc Filesystem
Adversaries may gather credentials from the proc filesystem or `/proc`. The proc filesystem is a pseudo-filesystem used as an interface to kernel data structures for Linux based systems managing virtual memory. For each process, the `/proc/<PID>/maps` file shows how memory is mapped within the process’s virtual address space. And `/proc/<PID>/mem`, exposed for debugging purposes, provides access to the process’s virtual address space.
T1606.002Forge Web Credentials: SAML Tokens
An adversary may forge SAML tokens with any permissions claims and lifetimes if they possess a valid SAML token-signing certificate. The default lifetime of a SAML token is one hour, but the validity period can be specified in the <code>NotOnOrAfter</code> value of the <code>conditions ...</code> element in a token. This value can be changed using the <code>AccessTokenLifetime</code> in a <code>LifetimeTokenPolicy</code>. Forged SAML tokens enable adversaries to authenticate across services that use SAML 2.0 as an SSO (single sign-on) mechanism.
Sources
AI-generated · no human review · this permalink is the shareable record for the finding · verify operationally critical claims against the linked primary source.