Medium severity5.9OSV Advisory· Published Jul 5, 2025· Updated Apr 15, 2026
CVE-2025-53605
CVE-2025-53605
Description
The protobuf crate before 3.7.2 for Rust allows uncontrolled recursion in the protobuf::coded_input_stream::CodedInputStream::skip_group parsing of unknown fields in untrusted input.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
protobufcrates.io | < 3.7.2 | 3.7.2 |
Affected products
1- Range: v1.0.24, v1.2.0, v1.2.1, …
Patches
24cb84f305c05f06992f46771Apply depth limit to unknown groups (#756)
1 file changed · +59 −12
protobuf/src/coded_input_stream/mod.rs+59 −12 modified@@ -511,6 +511,13 @@ impl<'a> CodedInputStream<'a> { } fn skip_group(&mut self) -> crate::Result<()> { + self.incr_recursion()?; + let ret = self.skip_group_no_depth_check(); + self.decr_recursion(); + ret + } + + fn skip_group_no_depth_check(&mut self) -> crate::Result<()> { while !self.eof()? { let wire_type = self.read_tag_unpack()?.1; if wire_type == WireType::EndGroup { @@ -631,19 +638,16 @@ impl<'a> CodedInputStream<'a> { /// Read message, do not check if message is initialized pub fn merge_message<M: Message>(&mut self, message: &mut M) -> crate::Result<()> { self.incr_recursion()?; - struct DecrRecursion<'a, 'b>(&'a mut CodedInputStream<'b>); - impl<'a, 'b> Drop for DecrRecursion<'a, 'b> { - fn drop(&mut self) { - self.0.decr_recursion(); - } - } - - let mut decr = DecrRecursion(self); + let ret = self.merge_message_no_depth_check(message); + self.decr_recursion(); + ret + } - let len = decr.0.read_raw_varint64()?; - let old_limit = decr.0.push_limit(len)?; - message.merge_from(&mut decr.0)?; - decr.0.pop_limit(old_limit); + fn merge_message_no_depth_check<M: Message>(&mut self, message: &mut M) -> crate::Result<()> { + let len = self.read_raw_varint64()?; + let old_limit = self.push_limit(len)?; + message.merge_from(self)?; + self.pop_limit(old_limit); Ok(()) } @@ -982,4 +986,47 @@ mod test { ); assert_eq!("field 3", input.read_string().unwrap()); } + + #[test] + fn test_shallow_nested_unknown_groups() { + // Test skip_group() succeeds on a start group tag 50 times + // followed by end group tag 50 times. We should be able to + // successfully skip the outermost group. + let mut vec = Vec::new(); + let mut os = CodedOutputStream::new(&mut vec); + for _ in 0..50 { + os.write_tag(1, WireType::StartGroup).unwrap(); + } + for _ in 0..50 { + os.write_tag(1, WireType::EndGroup).unwrap(); + } + drop(os); + + let mut input = CodedInputStream::from_bytes(&vec); + assert!(input.skip_group().is_ok()); + } + + #[test] + fn test_deeply_nested_unknown_groups() { + // Create an output stream that has groups nested recursively 1000 + // deep, and try to skip the group. + // This should fail the default depth limit of 100 which ensures we + // don't blow the stack on adversial input. + let mut vec = Vec::new(); + let mut os = CodedOutputStream::new(&mut vec); + for _ in 0..1000 { + os.write_tag(1, WireType::StartGroup).unwrap(); + } + for _ in 0..1000 { + os.write_tag(1, WireType::EndGroup).unwrap(); + } + drop(os); + + let mut input = CodedInputStream::from_bytes(&vec); + assert!(input + .skip_group() + .unwrap_err() + .to_string() + .contains("Over recursion limit")); + } }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-2gh3-rmm4-6rq5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-53605ghsaADVISORY
- github.com/stepancheg/rust-protobuf/commit/f06992f46771c0a092593b9ebf7afd48740b3ed6ghsaWEB
- github.com/stepancheg/rust-protobuf/issues/749nvdWEB
- rustsec.org/advisories/RUSTSEC-2024-0437.htmlghsaWEB
- crates.io/crates/protobufnvd
- rustsec.org/advisories/RUSTSEC-2024-0437nvd
News mentions
0No linked articles in our index yet.