Skip to content

Commit 5490c13

Browse files
authored
Merge pull request #312 from HackTricks-wiki/update_What_the_Miasma_Campaign_Reveals_About_the_New_S_9de20d9245b07fa3
What the Miasma Campaign Reveals About the New Supply Chain ...
2 parents 4bb7f5d + 1b27af5 commit 5490c13

3 files changed

Lines changed: 102 additions & 0 deletions

File tree

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- [Gh Actions - Artifact Poisoning](pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-artifact-poisoning.md)
1818
- [GH Actions - Cache Poisoning](pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-cache-poisoning.md)
1919
- [Gh Actions - Context Script Injections](pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-context-script-injections.md)
20+
- [GH Actions - npm Supply Chain Abuse](pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md)
2021
- [Accessible Deleted Data in Github](pentesting-ci-cd/github-security/accessible-deleted-data-in-github.md)
2122
- [Basic Github Information](pentesting-ci-cd/github-security/basic-github-information.md)
2223
- [Gitea Security](pentesting-ci-cd/gitea-security/README.md)

src/pentesting-ci-cd/github-security/abusing-github-actions/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,15 @@ import base64,os;exec(base64.b64decode(os.environ["STAGE2_B64"]))
745745

746746
Drop the line above into a file such as `evil.pth` inside `site-packages` and it will execute during Python startup. This is especially useful in build agents that continuously spawn Python tooling (`pip`, linters, test runners, release scripts).
747747

748+
#### npm supply-chain pivots from GitHub Actions
749+
750+
For `binding.gyp` / Phantom Gyp execution, wormable npm publishing with stolen CI identities, and the limits of trusted publishing provenance after workflow compromise, check:
751+
752+
{{#ref}}
753+
gh-actions-npm-supply-chain-abuse.md
754+
{{#endref}}
755+
756+
748757
#### Alternate exfil when outbound traffic is filtered
749758

750759
If direct exfiltration is blocked but the workflow still has a write-capable `GITHUB_TOKEN`, the runner can abuse GitHub itself as the transport:
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# GH Actions - npm Supply Chain Abuse
2+
3+
{{#include ../../../banners/hacktricks-training.md}}
4+
5+
## Overview
6+
7+
After an attacker gets code execution in a GitHub Actions release workflow, maintainer workstation, or package build pipeline, npm publishing becomes a high-impact pivot. The goal is usually to steal publisher identity material, publish malicious versions, and turn downstream installs into more credential-generation nodes.
8+
9+
Typical credential sources:
10+
11+
- `~/.npmrc`, `NPM_TOKEN`, registry sessions, and npm automation tokens.
12+
- GitHub PATs, `GITHUB_TOKEN`, release-bot credentials, SSH keys, and `.netrc` / git credential helpers.
13+
- GitHub Actions OIDC request material (`ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN`) in jobs with `id-token: write`.
14+
- Cloud credentials, Vault tokens, Kubernetes service account tokens, and `.env` files present in the release environment.
15+
16+
## Install-Time Execution Primitives
17+
18+
### Lifecycle hooks
19+
20+
The classic npm route is to publish a malicious package version with `preinstall`, `install`, `postinstall`, or `prepare` scripts. Any developer workstation or CI job that installs the version executes attacker-controlled code.
21+
22+
```json
23+
{
24+
"scripts": {
25+
"postinstall": "node ./scripts/collect.js"
26+
}
27+
}
28+
```
29+
30+
Defenders often monitor these scripts, so red-team reviews should also inspect less obvious execution paths.
31+
32+
### `binding.gyp` / node-gyp execution (Phantom Gyp)
33+
34+
Not every install-time execution path lives in `package.json` lifecycle hooks. `node-gyp`'s configure step looks for a `binding.gyp` file in the package directory, so a compromised publisher can shift execution into the native build path and bypass controls that only audit `preinstall` / `postinstall`.
35+
36+
Practical checks:
37+
38+
- Inspect the **published tarball**, not only the Git repo, for unexpected `binding.gyp`, `node-gyp`, or native-addon metadata in packages that should be pure JavaScript.
39+
- Treat a sudden `binding.gyp` addition as an execution primitive, especially if defenders rely on lifecycle-hook monitoring or `--ignore-scripts`.
40+
- Review release jobs that run `npm install`, `npm rebuild`, or dependency build steps after restoring untrusted artifacts/caches.
41+
42+
## Wormable npm Publishing
43+
44+
Once code runs in a maintainer workstation or release workflow, a single stolen registry identity can be turned into self-propagating package compromise:
45+
46+
1. Harvest maintainer secrets (`~/.npmrc`, PATs, OIDC request env vars, cloud creds, SSH keys).
47+
2. Enumerate packages the compromised identity or team can publish to.
48+
3. Republish malicious versions across each writable package.
49+
4. Let downstream installs create more credential-generation nodes.
50+
51+
Useful enumeration from a compromised npm identity:
52+
53+
```bash
54+
npm whoami
55+
npm access ls-packages
56+
npm access ls-collaborators <scope-or-package>
57+
```
58+
59+
Attackers usually prefer packages with frequent CI installs, transitive popularity, or release automation that will install the malicious version quickly.
60+
61+
## Trusted Publishing and Provenance Limits
62+
63+
Trusted publishing/OIDC removes long-lived static npm tokens, but it does not make a compromised release workflow safe. If the attacker controls code that runs in a job with `id-token: write`, the malicious release can still receive valid provenance because the legitimate workflow really built and published it.
64+
65+
Provenance answers **which workflow built this artifact**, not **whether the workflow, source tree, cache, or build steps were clean**.
66+
67+
High-signal review points:
68+
69+
- Workflows combining `id-token: write` with `npm publish`, `pnpm publish`, `changesets`, release bots, or custom publish wrappers.
70+
- Release jobs that restore caches or artifacts from lower-trust workflows before publishing.
71+
- Jobs that publish without human approval, environment protection rules, or a second reviewer.
72+
- Workflows that request OIDC before all build inputs have been verified.
73+
74+
## Hardening
75+
76+
- Use trusted publishing/OIDC instead of static npm tokens, but pair it with protected environments and human approval for sensitive scopes.
77+
- Add staged publishing / human 2FA approval for high-impact packages where possible.
78+
- Use `minimumReleaseAge` or equivalent dependency quarantine controls before consuming newly published package versions.
79+
- Separate cache keys by trust boundary and never execute restored cache contents before integrity checks.
80+
- Diff published tarballs against source repositories, and alert on unexpected native build metadata such as `binding.gyp`.
81+
- Disable or tightly review lifecycle scripts in CI (`npm config set ignore-scripts true`) where builds do not need them.
82+
- Monitor package access (`npm access ls-packages`) and remove stale maintainers, bots, and teams.
83+
84+
## References
85+
86+
- [What the Miasma campaign reveals about the new supply chain threat model and the underground market for developer credentials](https://www.tenable.com/blog/what-the-miasma-campaign-reveals-about-the-new-supply-chain-threat-model-and-the-underground)
87+
- [Trusted publishing for npm packages | npm Docs](https://docs.npmjs.com/trusted-publishers/)
88+
- [Staged publishing for npm packages | npm Docs](https://docs.npmjs.com/staged-publishing/)
89+
- [npm orgs | npm Docs](https://docs.npmjs.com/using-npm/orgs.html)
90+
- [node-gyp README](https://github.com/nodejs/node-gyp)
91+
92+
{{#include ../../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)