CVE-2022-25878 is a critical prototype pollution vulnerability in protobuf.js (npm package protobufjs), one of the most widely used JavaScript/TypeScript implementations of Google's Protocol Buffers. The flaw lives in how the library parses .proto schema definitions and JSON descriptors: a specially crafted "path" value passed into the internal util.setProperty helper — reachable through ReflectionObject.setParsedOption — lets an attacker write arbitrary properties onto Object.prototype. Because protobufjs is a foundational dependency for gRPC tooling, Firebase, Google Cloud client libraries, and countless internal RPC layers, this is the kind of transitive dependency that shows up in software bills of materials (SBOMs) across thousands of applications without teams realizing they're exposed. Public advisories rate the issue as critical, with a commonly cited CVSS v3.1 base score of 9.8, reflecting how a successful prototype pollution chain can cascade into denial of service, authorization bypass, or in the worst case remote code execution depending on how the polluted object is later consumed downstream.
What the vulnerability actually does
Prototype pollution vulnerabilities exploit JavaScript's prototypal inheritance model. When a library recursively walks an object graph and blindly assigns properties using attacker-controlled keys — including special keys like __proto__, constructor, or prototype — it can inject or overwrite properties on the base Object.prototype that every object in the runtime inherits from. In protobufjs, this happens during option parsing when building the internal reflection representation of a .proto file or a JSON-encoded descriptor. If an application accepts and parses untrusted .proto schemas or descriptor JSON — for example, a service that lets partners upload custom protobuf schemas, or a tool that compiles proto files submitted via CI — an attacker can smuggle a malicious path segment that reaches util.setProperty and pollutes the global object prototype.
The practical impact depends heavily on what the host application does afterward. Because polluted prototype properties affect every subsequent object created in the process, downstream code that checks for the presence of a property, merges configuration objects, or makes authorization decisions based on object shape can be silently subverted. In Node.js services this has repeatedly proven to be a stepping stone to denial-of-service crashes and, in combination with other unsafe patterns (like eval-adjacent template rendering or unsafe child_process invocation), to full remote code execution.
Affected versions and components
- Package:
protobufjs(npm) - Vulnerable versions: all versions prior to 6.11.3, and the 7.0.0 pre-release line prior to the general availability fix
- Fixed versions: 6.11.3 and later on the 6.x line; 7.0.0 and later on the 7.x line
- Affected function:
util.setProperty, reachable viaReflectionObject.setParsedOptionduring.proto/ JSON descriptor parsing
Because protobufjs is pulled in transitively by a large number of higher-level packages — gRPC-Node tooling, Firebase Admin SDK dependency chains, @grpc/proto-loader, various Google Cloud client libraries, and countless internal codegen pipelines — the effective blast radius is much larger than a direct dependency count would suggest. Organizations that never directly npm install protobufjs can still ship a vulnerable copy several levels deep in node_modules, which is precisely why lockfile-based dependency graphs matter more than manifest-level version pins when scoping this issue.
CVSS, EPSS, and KEV context
Public advisories (including the GitHub Security Advisory for this issue) score CVE-2022-25878 as Critical, with a CVSS v3.1 base score of 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) — reflecting a network-exploitable, low-complexity attack with no privileges or user interaction required, and a "high" impact rating across confidentiality, integrity, and availability. That headline score is intentionally worst-case: it assumes an application feeds fully attacker-controlled schema input into protobufjs and does nothing to sanitize downstream property access. In practice, exploitability is gated by whether an application actually parses untrusted .proto or JSON descriptor content, which meaningfully narrows the population of genuinely exploitable deployments even though the library itself is present almost everywhere.
EPSS (Exploit Prediction Scoring System) tracking for this CVE has generally sat in the low range rather than showing the kind of spike associated with actively weaponized, internet-scanned vulnerabilities — consistent with the fact that exploitation requires a specific, less common sink (untrusted schema parsing) rather than a generic network-facing listener. As of this writing, CVE-2022-25878 does not appear on the CISA Known Exploited Vulnerabilities (KEV) catalog, meaning there is no confirmed evidence of widespread in-the-wild exploitation tracked by CISA. That said, EPSS and KEV status are point-in-time signals, not guarantees — prototype pollution primitives are frequently chained with other bugs, and a library this deeply embedded in the npm ecosystem remains an attractive target for researchers and attackers alike. Teams should treat the absence of a KEV listing as "not yet observed," not "safe to ignore."
Timeline
- Root cause introduced: present across protobufjs 6.x releases prior to the fix, and in early 7.0.0 pre-releases, for an extended period before public disclosure.
- Public disclosure (~March 2022): The vulnerability was published as a GitHub Security Advisory and assigned CVE-2022-25878, describing the prototype pollution path through
util.setPropertyandReflectionObject.setParsedOption. - Patch release: Maintainers shipped fixed builds in 6.11.3 and 7.0.0, closing the vulnerable code path by hardening property assignment against unsafe keys.
- Ecosystem propagation: Downstream packages that bundled or pinned older protobufjs versions (gRPC tooling, codegen pipelines, various SDKs) required their own dependency bumps to fully clear the transitive exposure — a process that, as with most deep-dependency CVEs, lagged the upstream fix by weeks to months depending on how actively each maintainer tracked advisories.
- Ongoing exposure: Because protobufjs is so frequently vendored transitively, vulnerable copies continue to surface in dependency scans years after the fix shipped, particularly in older codegen output, vendored bundles, and monorepos with inconsistent lockfile hygiene.
Remediation steps
- Identify every copy, not just the direct dependency. Run
npm ls protobufjs(or the Yarn/pnpm equivalent) across every workspace and service, and check bundled/vendored copies inside generated gRPC or Firebase codegen output — those often escape a simple manifest grep. - Upgrade to a patched release. Move to
protobufjs@6.11.3or later on the 6.x line, orprotobufjs@7.0.0or later. If you depend on it transitively, bump the parent package (e.g.,@grpc/proto-loader, Firebase Admin SDK) to a version that has already updated its own dependency. - Force resolution where direct upgrades aren't immediately possible. Use
overrides(npm),resolutions(Yarn), orpnpm.overridesto pin the transitive protobufjs version to a patched release while you wait on upstream maintainers to bump their own manifests. - Audit and restrict untrusted schema parsing. If your application parses
.protofiles or JSON descriptors supplied by customers, partners, or any source outside your own build pipeline, treat that as an explicit trust boundary — validate schema structure before parsing, run the parser in a sandboxed/isolated process, or disallow user-supplied schemas entirely if the feature isn't essential. - Add defense-in-depth against prototype pollution generally. Freeze
Object.prototypein sensitive processes (Object.freeze(Object.prototype)), useObject.create(null)for maps built from untrusted keys, and avoid deep-merge utilities that don't explicitly guard against__proto__/constructor/prototypekeys. - Re-scan after remediation. Confirm the fix landed in the actual resolved dependency tree (lockfile), not just the manifest — a version bump in
package.jsonwithout a corresponding lockfile update, or a stalenode_modules, will leave the vulnerable code path in place. - Regenerate and redeploy affected artifacts. If vulnerable protobufjs code was baked into compiled bundles, container images, or codegen output before the fix, rebuild and redeploy those artifacts rather than assuming a dependency bump alone clears the exposure.
How Safeguard Helps
Finding CVE-2022-25878 in a scan is easy; knowing whether it's actually reachable in your codebase is the hard part, and that's exactly where Safeguard focuses. Our reachability analysis traces call paths from your application's entry points down into ReflectionObject.setParsedOption and util.setProperty, so you can immediately see whether untrusted input can actually reach the vulnerable sink — instead of treating every transitive hit on protobufjs as equally urgent. Griffin, Safeguard's AI-native remediation engine, correlates that reachability signal with your live SBOM (whether generated by Safeguard or ingested from existing CycloneDX/SPDX sources) to rank this finding against everything else in your backlog, and can open an auto-fix pull request that bumps protobufjs — and any parent packages still pinning a vulnerable range — to a patched version with the lockfile changes already resolved. For findings where a straight upgrade isn't yet available, Safeguard surfaces the specific untrusted-input paths so your team can add targeted mitigations, like sandboxing schema parsing, without waiting on the entire dependency tree to catch up. The result is fewer false alarms, faster triage, and a clear, auditable trail from "vulnerability disclosed" to "verified fixed in production."