CVE-2022-3509 is a denial-of-service vulnerability in Google's protobuf-java library, where crafted text-format input forces excessive object churn and long JVM garbage-collection pauses. It carries a CVSS 3.1 base score of 7.5 (High) and affects both the core and lite variants below the patched releases. If your Java services parse Protocol Buffers text format from any untrusted source, this one is worth a look.
What the vulnerability does
Protocol Buffers support a human-readable text format alongside the compact binary wire format. CVE-2022-3509 lives in the text-format parser. When the parser processes input containing multiple instances of non-repeated embedded messages that carry repeated or unknown fields, internal message objects get converted back and forth between mutable builder forms and immutable message forms. That conversion churn generates a flood of short-lived objects.
The result is not a crash from a null pointer or a buffer overflow. It is a resource-exhaustion problem: the JVM spends its time in garbage collection instead of doing useful work. A relatively small malicious payload can stall a service, which is the definition of an algorithmic-complexity denial of service. It is closely related to CVE-2022-3171, which hit the binary parser with the same class of bug, and CVE-2022-3510 in the message-set variant.
Affected and fixed versions
The flaw affects protobuf-java core and lite versions before these fixed releases:
- 3.16.3
- 3.19.6
- 3.20.3
- 3.21.7
If your resolved protobuf-java version is below the fix on its release line, you are exposed. The fix, in commit a3888f5, corrects the BuilderAdapter methods (setField, setRepeatedField, addRepeatedField) so builder instances are converted to immutable messages via buildPartial() rather than being passed around repeatedly. That eliminates the object thrashing that drives the GC pauses.
Note that this is the Java implementation specifically. The bug is in how protobuf-java handles builders, so protobuf libraries for other languages are tracked under different advisories.
How to check whether you are exposed
The tricky part with CVE-2022-3509 is that protobuf-java is very often a transitive dependency. You may never have written com.google.protobuf:protobuf-java in your build file, yet it arrives through gRPC, a cloud SDK, or a data-serialization library. Print the resolved dependency tree to find it.
For Maven:
mvn dependency:tree -Dincludes=com.google.protobuf:protobuf-java
For Gradle:
./gradlew dependencies --configuration runtimeClasspath | grep protobuf-java
Read the version that actually resolves, not the version any single library requested. Maven's nearest-wins resolution and Gradle's highest-wins can land you on a version different from what you expect.
Remediating CVE-2022-3509
The fix is a version bump, but because protobuf-java is usually transitive, forcing the version is often cleaner than editing a direct dependency.
In Maven, pin the safe version through dependencyManagement so it wins regardless of what pulls it in:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.21.7</version>
</dependency>
</dependencies>
</dependencyManagement>
In Gradle, use a resolution strategy or a constraint:
dependencies {
constraints {
implementation("com.google.protobuf:protobuf-java:3.21.7") {
because("CVE-2022-3509 DoS in text-format parsing")
}
}
}
After bumping, re-run the dependency tree to confirm nothing forces an older version back in, and run your integration tests. Protobuf is generally backwards compatible within a major line, so a bump from 3.19.x to 3.21.7 rarely breaks anything, but verify rather than assume.
Reducing the blast radius if you cannot patch immediately
If a patch has to wait for a release window, reduce exposure at the boundary. The vulnerable path is text-format parsing of untrusted input. Most production systems use the binary wire format between services and never parse attacker-supplied text format at all. Audit whether any endpoint accepts protobuf text format from the outside; if none does, your practical risk is low even before patching. Where you do accept it, add input size limits and rate limiting so a single caller cannot monopolize CPU.
Catching this class of issue continuously
CVE-2022-3509 is a textbook transitive-dependency problem: the vulnerable code is real, but it hides several layers down your build graph. That is exactly where manual tracking fails and automated software composition analysis helps, because an SCA tool such as Safeguard resolves the full dependency graph and flags the protobuf-java version even when nothing in your own manifest names it. Wire the scan into CI with a policy gate on high-severity findings so a regression that reintroduces the vulnerable version fails the build rather than shipping.
FAQ
Is CVE-2022-3509 remotely exploitable?
It requires the application to parse attacker-controlled Protocol Buffers text-format input. If your service exposes such a parsing path to untrusted callers, a crafted payload can trigger the DoS remotely. Systems that only use the binary wire format internally are far less exposed.
What versions of protobuf-java fix CVE-2022-3509?
Versions 3.16.3, 3.19.6, 3.20.3, and 3.21.7 contain the fix. Upgrade to the patched release on your current line or later.
How severe is CVE-2022-3509?
It has a CVSS 3.1 base score of 7.5, rated High. The impact is availability only; it does not by itself leak data or allow code execution, but a stalled service can still be a serious outage.
I never added protobuf-java to my project, why does a scanner flag it?
Because it is almost always a transitive dependency pulled in by gRPC, cloud SDKs, or serialization libraries. Run mvn dependency:tree or gradle dependencies to see which of your direct dependencies brings it in.