diff --git a/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md b/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md
index 89a0f54c91..75acaaf0d0 100644
--- a/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md
+++ b/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md
@@ -165,6 +165,29 @@ Trusted publishing/OIDC removes long-lived static npm tokens, but it does not ma
Provenance answers **which workflow built this artifact**, not **whether the workflow, source tree, cache, or build steps were clean**.[[1]](#references)[[2]](#references)[[13]](#references)[[15]](#references)
+### Build-to-publish privilege crossing
+
+A release job that installs dependencies and publishes in the same job gives install-time code the job's identity. In this abbreviated workflow, a malicious `postinstall` script reached by `npm ci` inherits the workflow-level `NODE_AUTH_TOKEN` and can request an OIDC token because `id-token: write` applies to the whole job, not just the publish step.[[19]](#references)[[21]](#references)
+
+```yaml
+env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+jobs:
+ release:
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - run: npm ci
+ - run: npm publish
+```
+
+`npm ci` requires an existing `package-lock.json` or `npm-shrinkwrap.json`; without one, this example fails rather than resolving a fresh malicious version. The poisoned version must be selected by the lockfile for this exact install path to run it.[[20]](#references)
+
+Moving `NODE_AUTH_TOKEN` to the `npm publish` step removes it from the install step, but **does not protect the publish command** if the attacker controls the package's publish-time scripts.[[19]](#references) npm runs `prepublishOnly`, `prepack`, `prepare`, `postpack`, `publish`, and `postpublish` around `npm publish`, so a token-bearing publish step remains an execution surface.[[6]](#references) Step-scoped environment variables also do not narrow `id-token: write`, which GitHub supports at workflow or job scope, not step scope.[[21]](#references)
+
+When assessing a release workflow, trace whether dependency installation, tests, artifact creation, and publication share a job with `id-token: write` or registry secrets.[[19]](#references) A separate build job with no publisher identity removes those credentials and OIDC request access from install-time code in that job; the privileged publish job can consume its output via an artifact.[[19]](#references) The artifact is still untrusted input: a malicious package or publish-time script in it can execute with the publisher identity. See [Artifact Poisoning](./#artifact-poisoning) for the cross-job trust boundary and [AWS - Federation Abuse](../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md#oidc---github-actions-abuse) for role-ARN discovery when the trusted provider is AWS.[[14]](#references)[[19]](#references)
+
ChainDrop implemented a repository-gated path that injected a Git-pinned `@opensearch/setup` dependency imitating the legitimate `@opensearch-project` scope. Review dependency diffs even when lifecycle scripts do not change.[[13]](#references)
High-signal review points:
@@ -221,5 +244,8 @@ Useful behavior-level signals from the same chain include:[[18]](#reference
- [16] [Malicious key-derivation telemetry commit in InjectiveLabs/injective-ts](https://github.com/InjectiveLabs/injective-ts/commit/01219285b16ce85c70cdf47a71a551ff5e41f1ed)
- [17] [Not-So-Anonymous Telemetry: The @injectivelabs/sdk-ts Backdoor](https://securitylabs.datadoghq.com/articles/not-so-anonymous-telemetry-injectivelabs-sdk-ts-backdoor)
- [18] [NPM Worm Compromises Hundreds of Popular npm Packages](https://securitylabs.datadoghq.com/articles/npm-worm-compromises-popular-npm-packages)
+- [19] [CI/CD Protected Build Jobs: Isolating Build and Publish Phases](https://labs.sra.io/posts/cicd_protected_build_jobs)
+- [20] [npm-ci | npm Docs](https://docs.npmjs.com/cli/v11/commands/npm-ci/)
+- [21] [Workflow syntax for GitHub Actions | GitHub Docs](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md b/src/pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
index 76e23c7759..5cd6edefc3 100644
--- a/src/pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
+++ b/src/pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
@@ -42,6 +42,7 @@ GitHub Actions can exchange a short-lived OIDC token for temporary AWS credentia
```
The `sub` values limit the role to the selected repository, pull-request runs, and the `main` branch ref. The role's permissions policy should independently enforce least privilege.[[1]](#references)[[4]](#references)[[6]](#references)
6. The role ARN is the identifier consumed by the action; the example stores it in the `READ_ROLE` secret. An ARN is not itself a credential, but an environment-scoped secret can be used when the workflow also uses protected environment rules.[[1]](#references)[[6]](#references)
+ - A compromised job with `id-token: write` still needs the target role ARN to exchange its GitHub OIDC token for AWS credentials.[[4]](#references)[[13]](#references) If the repository is checked out, a literal `role-to-assume` value may be visible in `.github/workflows/`; the ARN may also be in a job environment variable.[[4]](#references)[[13]](#references) A workflow reference to a secret reveals only the secret name, not its value.[[14]](#references) The ARN is not a security boundary: the IAM trust policy decides whether that workflow identity can assume the role.[[4]](#references)[[13]](#references) See [Build-to-publish privilege crossing](../../../pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md#build-to-publish-privilege-crossing) for the related npm job boundary.
7. Use `aws-actions/configure-aws-credentials` to exchange the GitHub OIDC token for temporary AWS credentials.[[4]](#references)[[7]](#references) The following workflow is an example:
```yaml
@@ -141,5 +142,7 @@ An explicit `sub` condition prevents other service accounts in the cluster or na
- [10] [IAM Roles for Service Accounts - eksctl](https://docs.aws.amazon.com/eks/latest/eksctl/iamserviceaccounts.html)
- [11] [Assign IAM roles to Kubernetes service accounts](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html)
- [12] [Get started with Amazon EKS - eksctl](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html)
+- [13] [CI/CD Protected Build Jobs: Isolating Build and Publish Phases](https://labs.sra.io/posts/cicd_protected_build_jobs)
+- [14] [Secrets - GitHub Docs](https://docs.github.com/en/actions/concepts/security/secrets)
{{#include ../../../banners/hacktricks-training.md}}