Skip to content

google-gax: rimraf appears build-only but is published as a production dependency (pulls vulnerable brace-expansion chain) #8969

Description

@sgarg17com

Summary

google-gax declares rimraf under dependencies, but rimraf does not appear
to be used by any shipped runtime code. Because rimraf@5 transitively depends
on glob@10 → minimatch@9 → brace-expansion@2, every consumer of google-gax
currently inherits GHSA-mh99-v99m-4gvg (brace-expansion, DoS via
unbounded expansion) in their production dependency tree.

If the declaration is indeed build-only or vestigial, moving it to
devDependencies (or removing it) would clear the advisory for all downstream
consumers without any code change.

Version

google-gax@5.0.8 (current latest at time of writing).

Dependency path

@google-cloud/firestore@8.7.0
└─ google-gax@5.0.8
   └─ rimraf@5.0.10
      └─ glob@10.5.0
         └─ minimatch@9.0.9
            └─ brace-expansion@2.1.2   ← GHSA-mh99-v99m-4gvg

The same tail is reachable via @google-cloud/pubsub and @google-cloud/tasks,
which also depend on google-gax.

Evidence that rimraf is not used at runtime

Against the published tarball / installed package for google-gax@5.0.8:

$ npm view google-gax@5.0.8 dependencies.rimraf
^5.0.1

$ npm view google-gax@5.0.8 devDependencies.rimraf
                       # (empty — it is a production dependency)

$ npm view google-gax@5.0.8 scripts --json | grep -i rimraf
                       # (no matches — no script references rimraf either)

$ grep -rE "require\(.rimraf.\)|from .rimraf." node_modules/google-gax/build/
                       # (no matches across 47 .js files)

So the package neither imports rimraf in its shipped output nor invokes it
from a lifecycle/utility script.

Why consumers cannot easily work around this

The obvious downstream mitigation — overriding brace-expansion to the patched
5.0.8breaks google-gax at runtime. minimatch@9.0.9 compiles to:

const brace_expansion_1 = __importDefault(require("brace-expansion"));
return (0, brace_expansion_1.default)(pattern);

brace-expansion@5.0.8's CommonJS build sets __esModule: true and exports only
a named expand, so __importDefault does not wrap it and
brace_expansion_1.default is undefined. Every brace-pattern match then throws
TypeError: ... is not a function. (minimatch@10 bumped its major precisely
for this export-shape change.) Note that brace-expansion's advisory range is
<=5.0.7, i.e. every 1.x/2.x/4.x backport is affected — 5.0.8 is the only
patched release, and minimatch@9 cannot consume it.

Consumers are therefore left with a scoped override such as:

"overrides": {
  "google-gax": { "rimraf": "^6.1.3" }
}

which is safe only because nothing in google-gax actually calls rimraf — but
it is a workaround that every downstream project has to discover and justify
independently.

Requested outcome

Whichever is correct for the package:

  1. Move rimraf to devDependencies (or drop it) if it is build-only/unused; or
  2. If it genuinely is required at runtime, bump the declared range to rimraf@^6,
    which resolves glob@13 → minimatch@10 → brace-expansion@^5.

Related

  • Update gaxios to 7.2.0 in gcp-metadata #8868gcp-metadata pins gaxios to an exact version; gaxios@7.1.3
    carries the same rimraf: ^5.0.1 declaration (also unused in its shipped
    build/), reaching the tree through google-auth-library → gcp-metadata.
    gaxios@7.3.0 dropped rimraf outright.

Environment

  • Node.js 22
  • npm 10
  • Reproducible from a clean install of @google-cloud/firestore@8.7.0 alone.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions