devtake.dev

protobuf.js RCE: a 52M/week npm package was one bad type name from code execution

GHSA-xq3m-2v4x-88gg hits protobuf.js ≤8.0.0 / ≤7.5.4. Attacker-controlled schemas executed arbitrary JS on decode. One-line fix patched it.

Editorial Team · · 4 min read · 3 sources
GitHub social card for the protobufjs/protobuf.js repository.
Image via GitHub (protobufjs/protobuf.js) · Source

A critical vulnerability in protobuf.js, Google’s JavaScript implementation of Protocol Buffers, let an attacker-controlled schema execute arbitrary code on decode. Endor Labs disclosed the flaw as GHSA-xq3m-2v4x-88gg with a CVSS score of 9.4. The package pulls roughly 52 million npm downloads a week. The fix is one line.

What broke

protobuf.js compiles message encoders and decoders on the fly from schema definitions. To build those functions, it concatenates type names into a JavaScript string and hands the result to the Function() constructor. It never sanitizes the identifiers.

If a type name in a .proto descriptor looks like plain text, everything works. If it looks like the closing paren of a function signature followed by a malicious body, that body runs the first time an application decodes a matching message. The Endor Labs write-up shows the shape: a type named User){process.mainModule.require("child_process").execSync("id");}function x( closes the generated function’s synthetic signature, inlines the payload, and opens a throwaway function to swallow the rest of the template.

The patch, commit 535df44, is exactly what you’d guess: name = name.replace(/\W/g, ""); before code generation. Strip non-word characters. Done. That the fix is one line is not a defense of the library. It’s the indictment.

Who’s affected

protobuf.js versions 8.0.0 and earlier on the 8.x branch and 7.5.4 and earlier on the 7.x branch are vulnerable. Patched releases are 8.0.1 (published April 4, 2026) and 7.5.5 (published April 15), per BleepingComputer. The Cyber Security Agency of Singapore issued a matching advisory.

The footprint is wide because protobuf.js is transitive for a lot of foundational code: @grpc/proto-loader, Firebase SDKs, most Google Cloud client libraries, and plenty of observability tooling. Most apps that ship Node code and talk to Google services pull it somewhere in the dependency tree.

Exploitation isn’t free, though. The attacker has to get a malicious schema into the loaded descriptor set. Endor Labs lists the realistic injection points:

  • gRPC reflection. Servers advertising their own schema via grpc.reflection.v1.ServerReflection.
  • Schema registries. Internal registries, external proto package repos.
  • API gateways that accept uploaded .proto files.
  • Multi-tenant platforms where users upload descriptors.
  • Third-party integrations where dev machines fetch schemas from the wire.

If your server loads protos only from bundled, version-controlled files, you’re mostly insulated. If anywhere in your system a schema comes from a network call, a customer, or a reflected service, that’s the exposure.

Timeline

Endor Labs researcher Cristian Staicu reported the flaw on March 2, 2026. The maintainers (affiliated with Google) patched on March 11. The npm releases followed: 8.0.1 on April 4 and 7.5.5 on April 15. The public write-up and the BleepingComputer story landed the same day. As of publication, no one has seen active exploitation in the wild.

That’s a fast, clean coordinated disclosure. It’s also the second major “descriptor-as-code” bug in six weeks. The Endor write-up draws the line to Orval’s CVE-2026-22785 and CVE-2026-23947, a similar OpenAPI-to-TypeScript codegen where summary and enum-description fields were interpolated unsanitized into generated source. Different tool, same mistake.

What this means for you

Update. Pin protobufjs to ≥8.0.1 or ≥7.5.5, depending on which major you’re on, and let Renovate push the bump through your transitive tree. @grpc/proto-loader and the Google Cloud SDKs will pull the fix; check your lockfile actually resolved to a patched version, because a cached tarball can land the old one.

Then audit where your app loads schemas from. If you run a public gRPC server with reflection on for developer convenience, consider turning it off in production or rate-limiting it to authenticated internal traffic. If you accept customer-supplied .proto files, that’s now a privileged operation and needs the same scrutiny you’d give a webhook handler. If you run a schema registry, assume any write to it is a code-execution vector until proven otherwise.

Beyond this CVE, the broader pattern is worth internalizing: any tool that takes structured input and generates code from identifier fields is one typo away from a 9.x CVSS. If you maintain one, the cheapest fix in the world is a character-class filter on anything you’re about to paste into a string-to-function call. Endor Labs’ point (schemas get treated as data but are actually templates that compile to code) is the correct framing. Treat them accordingly.

Sources

Mentioned in this article