- Endor Labs disclosed a CVSS 9.9 code-execution flaw in protobuf.js — the 52M-downloads-per-week JavaScript Protobuf library.
- Loading an attacker-controlled .proto schema is enough to run arbitrary code on the host.
- Here's the root cause, the one-line patch, and who's actually exposed.
TL;DR
GHSA-xq3m-2v4x-88gg is a critical (CVSS 9.9, CWE-94) arbitrary code execution flaw in protobuf.js, the most popular JavaScript Protocol Buffers library at ~52 million weekly npm downloads. Endor Labs researcher Cristian Staicu showed that loading an attacker-controlled .proto schema is enough to execute arbitrary JavaScript inside the host process the first time a message of that type is decoded. Upgrade to 7.5.5 or 8.0.1 immediately.
What's new
On April 16, 2026, Endor Labs published the writeup and the GitHub advisory landed publicly. The flaw was reported on March 2, confirmed March 9, patched on GitHub March 11, and shipped to npm on April 4 (8.0.1) and April 15 (7.5.5 backport). A working proof-of-concept is included in the disclosure.
Unlike the previous protobuf.js prototype-pollution issues (CVE-2022-25878, CVE-2023-36665), this one is direct code execution — no gadget, no chain. The library itself generates the attacker's payload as JavaScript and runs it.
Why it matters
protobuf.js sits deep in the Node.js ecosystem. It's a transitive dependency of @grpc/grpc-js, the Firebase Admin SDK, and most Google Cloud client libraries. If your service does anything dynamic with schemas — reads them from a registry, accepts them from a tenant, fetches them from a partner API — you may be exposed even if you've never typed protobufjs into a package.json.
The exploit precondition (attacker controls the schema) sounds narrow, but in practice it covers schema registries, plugin systems, multi-tenant ingest pipelines, gRPC reflection-style flows, and developer tooling that previews user-provided .proto files.
Technical facts
| Property | Value |
|---|---|
| Advisory | GHSA-xq3m-2v4x-88gg |
| CVSS 3.1 | 9.9 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) |
| CWE | CWE-94 — Improper Control of Generation of Code |
| Affected | protobufjs < 7.5.5 and 8.0.0 |
| Fixed | 7.5.5, 8.0.1+ |
| Weekly downloads | ~52 million |
| Discoverer | Cristian Staicu, Endor Labs |
Root cause: protobuf.js does not interpret schemas — it compiles them. The codegen path string-concatenates type names from the schema directly into JavaScript source, then evaluates that source via the Function() constructor. Identifier names are never validated or escaped.
A type name like User){process.mainModule.require("child_process").execSync("id");/* closes the synthetic function signature, injects arbitrary code, and comments out the trailing braces. The trigger chain is three calls: Root.fromJSON(maliciousSchema) → lookup the poisoned type → decode(buf) on any benign buffer. The payload runs in-process, with the privileges of the host application.
The patch is a single line in the codegen helper:
name = name.replace(/\W/g, "");That's it. Strip every non-word character before interpolation. The fact that this was the missing line for years explains why the vuln is so straightforward to exploit.
Comparison to past protobuf.js CVEs
| Year | ID | Class | Severity |
|---|---|---|---|
| 2022 | CVE-2022-25878 | Prototype pollution via util.setProperty | High |
| 2023 | CVE-2023-36665 | Prototype pollution via parse / load | Critical 9.8 (RCE possible) |
| 2026 | GHSA-xq3m-2v4x-88gg | Direct codegen injection | Critical 9.9 (RCE direct) |
The pattern is hard to ignore: every flaw is rooted in the same design choice — treating schemas as code rather than data. The 2026 issue removes the prototype-pollution gadget step entirely.
Who is actually exposed
- Multi-tenant SaaS that lets customers upload schemas — analytics ingest, schema registries, gRPC reflection.
- Apps that load schemas from remote sources — partner APIs, plugin marketplaces, internal schema registries (Buf, Confluent SR clones).
- Developer tooling that previews user-provided
.protofiles — IDE extensions, online playgrounds. - Indirect exposure — anything that pulls Firebase SDK, Google Cloud SDK, or
@grpc/grpc-js. Runnpm ls protobufjsfirst.
Limitations & what you can do today
- Upgrade
protobufjsto 7.5.5 or 8.0.1+. The patch is non-breaking. - Audit transitive dependencies:
npm ls protobufjs. Pin or override if a downstream SDK still resolves to a vulnerable version. - Treat any endpoint that loads a
.protoas aneval()sink. Apply the same trust controls — auth, integrity checks, allow-listing. - Prefer build-time compilation with
pbjsover dynamic schema loading in production paths. - Pin and verify reused schemas with checksums; track schema provenance.
Apps using only statically compiled stubs (no runtime .proto loading) are not affected. No in-the-wild exploitation has been reported as of the advisory.
What's next
A formal CVE assignment is pending. Expect a wave of pinned-version SDK releases from Google, Firebase, and the gRPC-JS team over the next few weeks. The deeper takeaway from Endor Labs is architectural: the "schema as code" pattern keeps producing critical bugs, and any library that compiles user input through Function() or eval() deserves the same scrutiny as a SQL string concatenation.
Sources: Endor Labs, BleepingComputer, GitHub Advisory, GitLab Advisory.