GHSA-7xpr-hc2w-34m9 Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service
CVE-2026-45799Maintainer summaryWire's protobuf group-skipping logic did not reject negative lengths before skipping a
length-delimited field inside a group. A crafted protobuf payload could cause Wire to throw an
unchecked runtime exception during decoding instead of the documented `IOException` /
`ProtocolException` failure path.This can crash services that decode untrusted protobuf payloads and only handle Wire's documented
checked decoding failures.Affected artifacts`com.squareup.wire:wire-runtime`Affected versions: vulnerable releases before `6.3.0`.Patched versions: `6.3.0` and later.Users should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.`com.squareup.wire:wire-runtime-jvm`Affected versions: vulnerable releases before `6.3.0`.Patched versions: `6.3.0` and later.Users should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.Wire 7 alpha releasesThe fix has been merged to `master` and will be included in the next Wire 7 alpha release. Until
that release is available, Wire 7 alpha users should avoid decoding untrusted protobuf payloads with
affected alpha versions or build from a commit containing the fix.FixThe issue is fixed in Wire `6.3.0`.The fix rejects negative lengths while skipping groups and throws `ProtocolException` instead of
allowing the reader to move to an invalid position and later throw an unchecked runtime exception.CreditReported by @TrekLaps.Technical detailsThe following technical details are based on the original report, updated by the maintainers to
reflect the assigned CVE, the supported fixed artifact, and the discontinued status of
`com.squareup.wire:wire-runtime-jvm`.`ByteArrayProtoReader32.skipGroup()` in `wire-runtime` did not validate that a
`LENGTH_DELIMITED` field's length is non-negative before calling `skip()`. A crafted protobuf
varint encodes `-128` as a signed `Int`. When `skip(-128)` runs, the internal position counter
underflows to an invalid negative position. The next `readByte()` accesses the source with that
negative position, throwing `ArrayIndexOutOfBoundsException`, a `RuntimeException` that escapes
Wire's documented `IOException` boundary and can crash the request handler.`ProtoAdapter.decode(byte[])` is declared to throw `IOException`. Callers following the documented
API may catch only `IOException`, so unchecked runtime exceptions from malformed input can escape
the expected error boundary.The originally confirmed vulnerable legacy versions include `5.3.1` and `5.3.3` for the
discontinued `com.squareup.wire:wire-runtime-jvm` coordinate. The supported replacement coordinate
is `com.squareup.wire:wire-runtime`, fixed in version `6.3.0`.Root causeIn the originally reported vulnerable code path, `ByteArrayProtoReader32.skipGroup()` read the
length as a signed `Int` and used it without validating that it was non-negative:The internal `skip()` implementation then accepted the negative count because the computed
position was not greater than the limit:The next read could then index the source with the invalid negative position:Wire already rejected negative lengths in normal length-delimited field decoding. The same
validation was missing from group-skipping code.The fix adds this validation when skipping groups:The fix was applied to both `ByteArrayProtoReader32.skipGroup()` and `ProtoReader.skipGroup()`.ReproductionThe following reproduction was provided for vulnerable legacy `wire-runtime-jvm` releases such as
`5.3.1` and `5.3.3`:Observed output on vulnerable versions:With the fix, the same payload is rejected with `ProtocolException`.Why this can affect any Wire-decoding service`skipGroup()` is called for any unknown field with wire type 3. An attacker can send an unknown
field, such as field 99, with wire type `START_GROUP`. The decoder skips it via `skipGroup()`
regardless of which message type the service uses, so no schema knowledge is required.Payload:Payload breakdown:
CVSS v3.1 score: 7.5