VYPR
Medium severity5.8NVD Advisory· Published Mar 16, 2025· Updated Apr 15, 2026

CVE-2024-58103

CVE-2024-58103

Description

Square Wire before 5.2.0 does not enforce a recursion limit on nested groups in ByteArrayProtoReader32.kt and ProtoReader.kt.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
com.squareup.wire:wire-runtimeMaven
< 5.2.05.2.0

Patches

2
b90e60c09bef

Enforce recursion limit on nested groups

https://github.com/square/wireBenoît QuenaudonSep 23, 2024via ghsa
4 files changed · +60 2
  • wire-runtime/src/commonMain/kotlin/com/squareup/wire/ByteArrayProtoReader32.kt+12 1 modified
    @@ -210,7 +210,18 @@ internal class ByteArrayProtoReader32(
           if (tagAndFieldEncoding == 0) throw ProtocolException("Unexpected tag 0")
           val tag = tagAndFieldEncoding shr TAG_FIELD_ENCODING_BITS
           when (val groupOrFieldEncoding = tagAndFieldEncoding and FIELD_ENCODING_MASK) {
    -        STATE_START_GROUP -> skipGroup(tag) // Nested group.
    +        STATE_START_GROUP -> {
    +          recursionDepth++
    +          try {
    +            if (recursionDepth > RECURSION_LIMIT) {
    +              throw IOException("Wire recursion limit exceeded")
    +            }
    +            // Nested group.
    +            skipGroup(tag)
    +          } finally {
    +            recursionDepth--
    +          }
    +        }
             STATE_END_GROUP -> {
               if (tag == expectedEndTag) return // Success!
               throw ProtocolException("Unexpected end group")
    
  • wire-runtime/src/commonMain/kotlin/com/squareup/wire/ProtoReader.kt+12 1 modified
    @@ -249,7 +249,18 @@ open class ProtoReader(private val source: BufferedSource) {
           if (tagAndFieldEncoding == 0) throw ProtocolException("Unexpected tag 0")
           val tag = tagAndFieldEncoding shr TAG_FIELD_ENCODING_BITS
           when (val groupOrFieldEncoding = tagAndFieldEncoding and FIELD_ENCODING_MASK) {
    -        STATE_START_GROUP -> skipGroup(tag) // Nested group.
    +        STATE_START_GROUP -> {
    +          recursionDepth++
    +          try {
    +            if (recursionDepth > RECURSION_LIMIT) {
    +              throw IOException("Wire recursion limit exceeded")
    +            }
    +            // Nested group.
    +            skipGroup(tag)
    +          } finally {
    +            recursionDepth--
    +          }
    +        }
             STATE_END_GROUP -> {
               if (tag == expectedEndTag) return // Success!
               throw ProtocolException("Unexpected end group")
    
  • wire-runtime/src/commonTest/kotlin/com/squareup/wire/ProtoReader32Test.kt+18 0 modified
    @@ -15,9 +15,12 @@
      */
     package com.squareup.wire
     
    +import com.squareup.wire.ReverseProtoWriterTest.Person
     import kotlin.test.Test
     import kotlin.test.assertEquals
    +import kotlin.test.assertFailsWith
     import okio.ByteString.Companion.decodeHex
    +import okio.IOException
     
     class ProtoReader32Test {
       @Test fun packedExposedAsRepeated() {
    @@ -58,5 +61,20 @@ class ProtoReader32Test {
         reader.endMessageAndGetUnknownFields(secondToken)
       }
     
    +  /** We had a bug where we weren't enforcing recursion limits for groups. */
    +  @Test fun testSkipGroupNested() {
    +    val data = ByteArray(50000) {
    +      when {
    +        it % 2 == 0 -> 0xa3.toByte()
    +        else -> 0x01.toByte()
    +      }
    +    }
    +
    +    val failed = assertFailsWith<IOException> {
    +      Person.ADAPTER.decode(data)
    +    }
    +    assertEquals("Wire recursion limit exceeded", failed.message)
    +  }
    +
       // Consider pasting new tests into ProtoReaderTest.kt also.
     }
    
  • wire-runtime/src/commonTest/kotlin/com/squareup/wire/ProtoReaderTest.kt+18 0 modified
    @@ -15,10 +15,13 @@
      */
     package com.squareup.wire
     
    +import com.squareup.wire.ReverseProtoWriterTest.Person
     import kotlin.test.Test
     import kotlin.test.assertEquals
    +import kotlin.test.assertFailsWith
     import okio.Buffer
     import okio.ByteString.Companion.decodeHex
    +import okio.IOException
     
     class ProtoReaderTest {
       @Test fun packedExposedAsRepeated() {
    @@ -59,5 +62,20 @@ class ProtoReaderTest {
         reader.endMessageAndGetUnknownFields(secondToken)
       }
     
    +  /** We had a bug where we weren't enforcing recursion limits for groups. */
    +  @Test fun testSkipGroupNested() {
    +    val data = ByteArray(50000) {
    +      when {
    +        it % 2 == 0 -> 0xa3.toByte()
    +        else -> 0x01.toByte()
    +      }
    +    }
    +
    +    val failed = assertFailsWith<IOException> {
    +      Person.ADAPTER.decode(Buffer().write(data))
    +    }
    +    assertEquals("Wire recursion limit exceeded", failed.message)
    +  }
    +
       // Consider pasting new tests into ProtoReader32Test.kt also.
     }
    

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

4

News mentions

0

No linked articles in our index yet.