{"uuid": "8764e433-13fc-4784-af2d-3b9ebeab2442", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2025-36852", "type": "seen", "source": "https://gist.github.com/vctqs1/16984a29e211c7ea8c9c8c878489d85d", "content": "# Nx Self-Hosted Remote Cache Vulnerability \u2014 Closing the Nx CREEP Gap With One IAM Condition\n\n## TL;DR\n\nIf you're using deprecated Nx self-hosted remote cache packages like `@nx/gcs-cache`, one immediate mitigation for the CREEP vulnerability is:\n\n- allow PR builds to restore cache artifacts\n- allow only trusted branches (`main`) to write cache artifacts\n- enforce this at the GCP IAM layer using Workload Identity Federation conditions\n\nThis is **not** a replacement for proper namespace isolation, but it meaningfully reduces risk while you plan the long-term architecture.\n\n---\n\n## Table of Contents\n\n- [Background](#background)\n- [Why CREEP Works](#why-creep-works)\n- [Required WIF Attribute Mapping](#required-wif-attribute-mapping)\n- [Practical Mitigation on GCP](#practical-mitigation-on-gcp)\n- [CI Configuration](#ci-configuration)\n- [Trade-Offs](#trade-offs)\n- [Long-Term Fix](#long-term-fix)\n- [Notes](#notes)\n- [References](#references)\n\n---\n\n## Background\n\nNx recently disclosed the CREEP vulnerability (CVE-2025-36852) affecting self-hosted remote cache packages such as:\n\n- `@nx/gcs-cache`\n- `@nx/s3-cache`\n- `@nx/azure-cache`\n- `@nx/shared-fs-cache`\n\nReferences:\n- https://nx.dev/blog/creep-vulnerability-build-cache-security#the-creep-vulnerability\n- https://nx.dev/docs/reference/deprecated/self-hosted-cache-packages\n\nOne important nuance:\n\nFor many private repositories, this is usually not a \u201crandom internet attacker\u201d scenario.\n\nThe attack generally requires someone who can:\n- open PRs\n- modify CI workflows\n- access the contribution pipeline\n\nIn practice, that often means:\n- internal developers\n- contractors\n- compromised contributor accounts\n- insiders with repository access\n\nSo the realistic risk model is often a CI trust-boundary problem inside engineering workflows.\n\n---\n\n## Why CREEP Works\n\nThe vulnerability itself is already well explained by the Nx team:\nhttps://nx.dev/blog/creep-vulnerability-build-cache-security#the-creep-vulnerability\n\nIn simplified form:\n\n1. An attacker opens a PR with source files identical to `main`\n2. The attacker changes the CI workflow instead of the application source\n3. The PR build uploads poisoned artifacts into remote cache\n4. `main` later restores the poisoned cache artifact and skips rebuilding\n\nThe critical issue is this:\n\n&gt; PR builds and trusted branch builds both writing into the same remote cache location.\n\nOr more simply:\n\n`Single shared cache location`\n\nOnce untrusted and trusted builds share the same writable cache location, cache poisoning becomes possible.\n\n---\n\n## Required WIF Attribute Mapping\n\nThe IAM condition depends on the GitHub branch reference being exposed through Workload Identity Federation attributes.\n\nThis mitigation requires Workload Identity Federation exposing:\n\n```txt\nattribute.ref\n```\n\nmapped from:\n\n```txt\nassertion.ref\n```\n\nExample:\n\n```hcl\nattribute_mapping = {\n  \"google.subject\" = \"assertion.sub\"\n  \"attribute.ref\"  = \"assertion.ref\"\n}\n```\n\nIf your provider mapping does not expose the Git reference, IAM conditions cannot evaluate branch names.\n\nDefinitely verify this with whoever manages your cloud IAM/WIF configuration.\n\n---\n\n## Practical Mitigation on GCP\n\nIf you're using:\n- Google Cloud Storage\n- Workload Identity Federation\n- GitHub Actions\n\nyou can immediately reduce the risk by enforcing cache write permissions at the IAM layer.\n\nThe goal is simple:\n\n- trusted branches (`main`) can write cache artifacts\n- PR builds can only restore cache artifacts\n- untrusted workflows cannot publish poisoned artifacts into the shared cache location\n\n### Example Terraform IAM Binding\n\nExample Terraform configuration for allowing only the `main` branch to upload cache artifacts:\n\n```hcl\nresource \"google_storage_bucket_iam_binding\" \"nx_cache_main_write\" {\n  bucket = google_storage_bucket.nx_cache.name\n  role   = \"roles/storage.objectCreator\"\n\n  members = [\n    \"principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github_pool.name}/attribute.repository/my-org/my-repo\"\n  ]\n\n  condition {\n    title       = \"main_branch_write_only\"\n    description = \"Allow cache writes only from main branch GitHub Actions runners\"\n    expression  = \"attribute.ref == \\\"refs/heads/main\\\"\"\n  }\n}\n```\n\nReference:\nhttps://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_iam#google_storage_bucket_iam_binding\n\nThis configuration means:\n\n- GitHub Actions runners authenticate through Workload Identity Federation\n- only workflows running from `refs/heads/main` can upload cache artifacts\n- PR workflows remain read-only cache consumers\n\nSince GitHub Actions tokens expose refs like:\n\n```txt\nrefs/pull//merge\n```\n\nGCP denies the upload request at the IAM layer before the cache artifact can be written.\n\nYou may also want separate IAM bindings for:\n- release branches\n- production workflows\n- isolated PR cache namespaces\n- dedicated cache readers\n\n---\n\n## CI Configuration\n\nOne additional step is configuring Nx to operate in read-only mode for PR builds.\n\nBecause the IAM policy only allows `main` to upload cache artifacts, PR workflows attempting cache writes would otherwise receive permission errors from GCS.\n\n```yaml\nenv:\n  NX_POWERPACK_CACHE_MODE: ${{ github.ref_name == 'main' &amp;&amp; 'read-write' || 'read-only' }}\n```\n\n`NX_POWERPACK_CACHE_MODE` is already supported internally by Nx Powerpack remote cache implementations such as `@nx/gcs-cache`.\n\n\n\nReference:\nhttps://www.npmjs.com/package/@nx/gcs-cache?activeTab=code\n\nThis setup gives you:\n\n| Branch Type | Cache Restore | Cache Upload |\n|---|---|---|\n| PR | \u2705 | \u274c |\n| main | \u2705 | \u2705 |\n\nThe IAM condition remains the actual security boundary.\n\n`NX_POWERPACK_CACHE_MODE` mainly helps Nx behave correctly inside CI and suppresses permission warnings from failed cache upload attempts in PR builds.\n\n---\n\n## Trade-Offs\n\nThis mitigation intentionally sacrifices one feature:\n\n### Loss of intra-PR incremental remote caching\n\nThat means:\n- each new PR commit rebuilds from trusted baseline cache\n- PR builds cannot reuse artifacts generated by earlier commits in the same PR\n\nHowever:\n- PRs still benefit from warm cache restores from `main`\n- trusted branches still retain full remote cache performance\n\nFor many teams, this is an acceptable short-term trade-off.\n\n---\n\n## Long-Term Fix\n\nThe long-term solution is proper cache namespace isolation.\n\nExample:\n\n```txt\nmain/\nrelease/\npr//\n```\n\nwith strict write boundaries between trust levels.\n\nNx also discusses this approach here:\nhttps://nx.dev/blog/creep-vulnerability-build-cache-security#the-creep-vulnerability\n\nThis IAM mitigation should be treated as:\n- a risk reduction measure\n- not a permanent architectural replacement\n\n---\n\n## Notes\n\nThis write-up describes one possible infrastructure-level mitigation strategy for reducing the blast radius of the Nx CREEP vulnerability on GCP-based CI systems.\n\nIt is not official Nx guidance and should not be treated as a replacement for proper remote cache isolation.\n\n---\n\n## References\n\n- Nx CREEP vulnerability write-up  \n  https://nx.dev/blog/creep-vulnerability-build-cache-security#the-creep-vulnerability\n\n- Deprecated Nx self-hosted cache packages  \n  https://nx.dev/docs/reference/deprecated/self-hosted-cache-packages\n\n- Nx GCS cache package  \n  https://www.npmjs.com/package/@nx/gcs-cache?activeTab=code\n\n- Nx self-hosted caching docs  \n  https://20.nx.dev/recipes/running-tasks/self-hosted-caching\n\n- Terraform Google Storage Bucket IAM Binding  \n  https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_iam#google_storage_bucket_iam_binding\n\n- Emily Xiong\u2019s deep dive into Nx self-hosted cache internals  \n  https://emilyxiong.medium.com/exploring-of-nx-self-hosted-cache-5bc39bd2ed7f", "creation_timestamp": "2026-05-29T10:48:35.000000Z"}