Vulnerabilities in pkg:maven/com.squareup.wire/wire-runtime

PACKAGE
Advisory Identifier: GHSA-9rm7-3qhh-h2mc
Advisory Summary

CVE-2026-63126 is a HIGH (CVSS 7.5) unauthenticated decoder crash vulnerability (CWE-190: Integer Overflow or Wraparound) affecting Wire libraries in the Maven ecosystem. The issue involves unauthenticated decoder crash via 32-bit length integer overflow in bytearrayprotoreader32 (incomplete fix of cve-2026-45799). Remediation is available by upgrading affected packages to version 6.4.5, 7.0.0-alpha04.

3 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:maven/com.squareup.wire/wire-runtime

3 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:maven/com.squareup.wire/wire-runtime. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-9rm7-3qhh-h2mc CVE-2026-63126 HIGH Wire: Unauthenticated decoder crash via 32-bit length integer overflow in ByteArrayProtoReader32 (incomplete fix of CVE-2026-45799)
GHSA-7xpr-hc2w-34m9 CVE-2026-45799 HIGH Wire: skipGroup() missing negative-length check allows 10-byte payload to crash any Wire-decoding service
GHSA-pwf9-q62p-v7wc CVE-2024-58103 MODERATE Wire has Uncontrolled Recursion on Nested Groups

CVE-2026-63126 at a Glance

CVE Identifier CVE-2026-63126
GHSA Identifier GHSA-9rm7-3qhh-h2mc
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-190: Integer Overflow or Wraparound
Affected Product Wire
Package Ecosystem Maven
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-63126

To remediate this vulnerability, upgrade all affected Wire dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

com.squareup.wire:wire-runtime fixed: 6.4.5
<dependency>
    <groupId>com.squareup.wire</groupId>
    <artifactId>wire-runtime</artifactId>
    <version>6.4.5</version>
</dependency>
com.squareup.wire:wire-runtime fixed: 7.0.0-alpha04
<dependency>
    <groupId>com.squareup.wire</groupId>
    <artifactId>wire-runtime</artifactId>
    <version>7.0.0-alpha04</version>
</dependency>
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

mvn dependency:tree -Dincludes=com.squareup.wire

How to Check if You Are Affected

To determine whether your Java application is affected by CVE-2026-63126, inspect your build dependencies using the Maven Dependency Plugin:

mvn dependency:tree -Dincludes=com.squareup.wire

Analyze the terminal output to locate any version of Wire in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 6.4.5), your application is affected.

Note: The mvn dependency:tree -Dincludes=com.squareup.wire command inspects the resolved dependency graph declared in your project's POM files; it does not perform automated security scanning or inspect runtime dynamic classpaths. Always verify runtime container classpaths and shaded JARs.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-190: Integer Overflow or Wraparound, where the product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. this occurs when an integer value is incremented to a value that is too large to store in the associated representation. when this occurs, the value may become a very small or negative number. In Wire, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

Wire's protobuf decoders did not consistently validate attacker-controlled length-delimited sizes against the current reader bounds before computing cursor, limit, or pointer positions. In the Kotlin runtime, `ProtoAdapter.decode(ByteArray)` and `ProtoAdapter.decode(ByteString)` use the `ProtoReader32` fast path implemented by `ByteArrayProtoReader32`. In `ByteArrayProtoReader32.internalNextLengthDelimited()`, Wire read an untrusted varint length into an `Int` and rejected only negative values. A length such as `2147483647` is non-negative, so it passed that check, but `pos + length` overflowed the signed 32-bit cursor and produced a negative `limit`. The following `if (limit > pushedLimit)` guard did not catch this because the overflowed value was negative. That invalid limit then reached string, bytes, skip, and scalar-reading paths as an invalid byte count or invalid range. Instead of failing as a checked decode error such as `IOException`, malformed input could throw unchecked runtime exceptions including `IllegalArgumentException` and `ArrayIndexOutOfBoundsException`. Applications commonly treat malformed protobuf input as an expected decode failure; unchecked runtime exceptions escaping that boundary can crash request handling or the process. The original report is a sibling of the negative-length skipped-group bug fixed as CVE-2026-45799. It is not the same bug. The length in this advisory is positive, and the overflow occurs when setting a length-delimited message limit, not only when skipping a group. While auditing for the same bug class, related boundary flaws were also found and fixed: - Kotlin `ProtoReader` now validates logical message limits before varint, fixed32, fixed64, and skip operations. The originally reported byte-array overflow payload did not reproduce as the same signed overflow in `ProtoReader`, because that reader tracks positions as `Long`, but the streaming reader still needed consistent current-message-limit enforcement. - Swift `ReadBuffer.readVarint()` read `pointer.pointee` before checking that one byte remained. A tag-only varint field could read past the end of the buffer. - Swift `ReadBuffer.verifyAdditional(count:)` formed `pointer.advanced(by: count)` before proving the requested `count` fit within the remaining buffer, so pointer arithmetic ran before the bounds were established. (The distinct Swift negative-length `skipGroup()` crash is tracked separately as GHSA-86wm-r4c5-2rc9 / CVE-2026-61695; this advisory covers the positive/oversized-length boundary failures.) - Swift nested-message decoding and packed-repeated decoding computed end pointers from untrusted lengths before validating that the bytes were present. - Swift packed-repeated decoding reserved array capacity from an untrusted length before validating that the length existed in the current buffer. - Swift size-delimited decoding converted an untrusted `UInt64` varint size to `Int` without exactness or availability checks. On platforms where the value is not representable, this could trap. The fix enforces a single invariant across the hardened readers: every decoded or skipped byte count must be non-negative and no larger than the remaining bytes in the current logical message limit before any cursor, pointer, limit, allocation, or slice is advanced. ### Impact An attacker who can supply protobuf bytes to an application using affected Wire decoders can trigger a denial of service by causing decode to fail with unchecked runtime failures or traps rather than normal malformed-input decode errors. Known impact: - Availability impact only. - No known confidentiality impact. - No known integrity impact. - No known code execution. Attack requirements: - The application decodes attacker-controlled protobuf bytes with Wire. - No authentication is required if the decoding endpoint is reachable without authentication. - A single short malformed protobuf payload is sufficient for the Kotlin byte-array fast path. Most directly affected Kotlin entry points: - `ProtoAdapter.decode(ByteArray)` - `ProtoAdapter.decode(ByteString)` Adjacent Kotlin path hardened by this fix: - `ProtoAdapter.decode(BufferedSource)` - direct use of `ProtoReader` Affected Swift entry points: - Swift `ProtoDecoder` and `ProtoReader` APIs when decoding attacker-controlled `Data` or buffers. ### Proof of concept and regression payloads These payloads are intentionally small and should be treated as malformed protobuf input. After the fix, they must fail with normal decode errors such as `IOException`, `EOFException`, or `ProtoDecoder.Error.unexpectedEndOfData`, not unchecked runtime exceptions, traps, out-of-bounds reads, or large allocations. #### Kotlin byte-array known length-delimited field Hex: ```text 0A FF FF FF FF 07 ``` Meaning: - `0A`: field 1, length-delimited - `FF FF FF FF 07`: varint length `2147483647` Pre-fix behavior observed through `Person.ADAPTER.decode(byteArray)`: ```text java.lang.IllegalArgumentException: startIndex: 6 > endIndex: -2147483643 ``` Expected fixed behavior: ```text IOException / EOFException ``` #### Kotlin byte-array unknown length-delimited field Hex: ```text 1A FF FF FF FF 07 ``` Meaning: - `1A`: field 3, length-delimited - `FF FF FF FF 07`: varint length `2147483647` Pre-fix behavior observed: ```text ArrayIndexOutOfBoundsException ``` Expected fixed behavior: ```text IOException / EOFException ``` #### Kotlin byte-array skipped group containing oversized positive length Hex: ```text 0B 0A FF FF FF FF 07 0C ``` Meaning: - `0B`: start group, field 1 - `0A`: nested field 1, length-delimited - `FF FF FF FF 07`: varint length `2147483647` - `0C`: end group, field 1 Expected fixed behavior: ```text IOException / EOFException ``` #### Kotlin current-message-limit fixed32 boundary Hex: ```text 02 0D 05 00 00 00 ``` Meaning: - `02`: outer length-delimited message length is 2 bytes - `0D`: nested field 1, fixed32 - `05 00 00 00`: enough bytes remain in the underlying source, but not inside the current logical message limit Expected fixed behavior: ```text EOFException ``` This covers the invariant that scalar reads must not cross the current length-delimited message boundary even when the underlying source has more bytes available. #### Swift tag-only varint value Hex: ```text 08 ``` Meaning: - `08`: field 1, varint - Missing varint value byte Pre-fix risk: - `ReadBuffer.readVarint()` could dereference `pointer.pointee` before verifying that a byte remained. Expected fixed behavior: ```text ProtoDecoder.Error.unexpectedEndOfData ``` #### Swift nested message with oversized positive length Hex: ```text 12 FF FF FF FF 07 ``` Meaning: - `12`: field 2, length-delimited - `FF FF FF FF 07`: varint length `2147483647` Pre-fix risk: - Nested message decoding computed an end pointer from an untrusted length before proving that the buffer contained that many bytes. Expected fixed behavior: ```text ProtoDecoder.Error.unexpectedEndOfData ``` #### Swift packed repeated field with oversized positive length Hex: ```text 0A FF FF FF FF 07 ``` Meaning: - `0A`: field 1, length-delimited packed repeated field - `FF FF FF FF 07`: varint length `2147483647` Pre-fix risk: - Packed repeated decoding could reserve capacity based on an untrusted length before proving the bytes were present. Expected fixed behavior: ```text ProtoDecoder.Error.unexpectedEndOfData ``` #### Swift size-delimited stream with unrepresentable size Hex: ```text FF FF FF FF FF FF FF FF FF 01 ``` Meaning: - Size-delimited message length varint `UInt64.max` Pre-fix risk: - `ProtoDecoder.decodeSizeDelimited(_:from:)` converted the untrusted `UInt64` to `Int` without exactness checking. Expected fixed behavior: ```text ProtoDecoder.Error.unexpectedEndOfData ``` ### Root cause The vulnerable code mixed three operations that must remain separate: 1. Decode an untrusted protobuf length. 2. Validate that the length is non-negative and fits within the current logical message boundary. 3. Advance the cursor, pointer, limit, slice, or allocation based on that length. In the vulnerable paths, step 3 happened before step 2 was complete. For Kotlin `ByteArrayProtoReader32`, this caused signed integer wraparound in `pos + length`. For Swift, related pointer and allocation operations could be performed before proving the requested bytes existed. ### Fix The fix centralizes checked cursor and pointer advancement. Kotlin changes: - `ByteArrayProtoReader32` now validates constructor invariants for `pos` and `limit`. - `ByteArrayProtoReader32` now uses shared helpers to: - reject negative lengths, - compute checked limits, - compute remaining bytes in the current logical limit, - validate before `skip`, - validate before string and bytes reads, - validate before fixed32 and fixed64 reads. - `ProtoReader` now mirrors the same logical-boundary model for: - length-delimited limit calculation, - skipped length-delimited fields, - varint reads, - fixed32 reads, - fixed64 reads, - current-message remaining-byte calculations. Swift changes: - `ReadBuffer` now computes checked end pointers only after confirming `count >= 0` and `count <= remaining`. - `ReadBuffer.readVarint()` verifies one byte remains before each byte dereference. - `ReadBuffer.readBuffer(count:)`, `readData(count:)`, `readFixed32()`, and `readFixed64()` compute the checked new pointer before reading and advancing. - `ProtoReader.beginMessage()` validates nested message lengths before storing a message-end pointer. - Packed repeated decoding validates the packed field length before preallocation and before constructing the loop boundary. - `ProtoDecoder.decodeSizeDelimited(_:from:)` converts sizes with `Int(exactly:)` and verifies that the full message bytes exist before constructing a child buffer. Fixed in PR #3635: - https://github.com/square/wire/pull/3635 - Fix commit `25ebcabb9ab7f12d1d77af75ecbc51726fddc015` ### Workarounds The recommended remediation is to upgrade to a patched release. Partial mitigations if an immediate upgrade is not possible: - Reject or cap untrusted protobuf message sizes before passing bytes to Wire. - Prefer decoding from a bounded source where possible rather than decoding unbounded attacker-controlled byte arrays. - Treat unchecked runtime exceptions from protobuf decode as malformed-input failures at service trust boundaries so they cannot crash the process. - For Swift, do not pass untrusted size-delimited streams or `Data` directly to affected decoders without an outer size cap and exception/error boundary. These mitigations reduce exposure but do not fully fix the parser bugs. ### Detection A crash or error may contain one of the following symptoms when processing malformed protobuf bytes: ```text IllegalArgumentException: startIndex: 6 > endIndex: -2147483643 ArrayIndexOutOfBoundsException IndexOutOfBoundsException unexpected unchecked RuntimeException during ProtoAdapter.decode(ByteArray) Swift trap during Int conversion from an untrusted protobuf size Swift unexpected pointer/buffer failure while reading malformed varints or length-delimited values ``` The absence of these exact messages does not prove safety. Any unchecked exception, trap, or process crash while decoding malformed length-delimited protobuf input should be investigated. ### Verification Regression tests added: - `ProtoReader32Test.lengthDelimitedRejectsPositiveLengthOverflow` - `ProtoReader32Test.fixed32CannotReadPastLengthDelimitedLimit` - `ProtoReaderTest.fixed32CannotReadPastLengthDelimitedLimit` - `ProtoReaderTests.testReadVarintRejectsMissingValue` - `ProtoReaderTests.testNestedMessageRejectsOversizedLength` - `ProtoReaderTests.testPackedRepeatedRejectsOversizedLengthBeforePreallocation` - `ProtoDecoderTests.testDecodeSizeDelimitedRejectsUnrepresentableSize` Focused verification command: ```bash ./gradlew :wire-runtime:jvmTest :wire-runtime-swift:test ``` Expected result: ```text BUILD SUCCESSFUL ``` ### Relationship to related advisories This is a distinct vulnerability from the negative-length issues. It is a different bug class — a positive, non-negative length (for example `2147483647`) that passes the existing `length < 0` check but still overflows the signed 32-bit cursor or crosses the current message boundary — and it has a separate fix (PR #3635, not the negative-length PRs). - `CVE-2026-45799` / `GHSA-7xpr-hc2w-34m9` fixed the original Kotlin/JVM negative-length skipped-group crash (Wire `6.3.0`). The non-negative overflow described here was not covered by that check and remained exploitable through `6.4.4`. - `GHSA-86wm-r4c5-2rc9` / `CVE-2026-61695` covers the Swift negative-length `skipGroup()` crash (PR #3616). The Swift hardening in this advisory (PR #3635) instead addresses positive/oversized-length overflow, buffer over-read, and unrepresentable-size conversions in the Swift readers.

CVE-2026-63126 Affected Wire Versions

2 component(s)
Fixed Versions:
6.4.57.0.0-alpha04
Product / Package Ecosystem Affected Versions Fixed Version
com.squareup.wire:wire-runtime
Maven
< 6.4.5
6.4.5
com.squareup.wire:wire-runtime
Maven
≥ 7.0.0-alpha01
< 7.0.0-alpha04
7.0.0-alpha04

References

Frequently Asked Questions

What is CVE-2026-63126?
CVE-2026-63126 is a security vulnerability in Wire involving Unauthenticated decoder crash via 32-bit length integer overflow in ByteArrayProtoReader32 (incomplete fix of CVE-2026-45799) under CWE-190: Integer Overflow or Wraparound.
Which Wire versions are affected?
Affected versions include releases prior to 6.4.5, 7.0.0-alpha04 across affected packages: com.squareup.wire:wire-runtime.
What version fixes CVE-2026-63126?
Upgrading to 6.4.5, 7.0.0-alpha04 (or the latest patched release for your respective branch) resolves the vulnerability.
Is wire-runtime affected?
Yes, com.squareup.wire:wire-runtime is affected in releases prior to 6.4.5, 7.0.0-alpha04. Upgrade your dependency to 6.4.5, 7.0.0-alpha04 or later.
What is the CVSS score of CVE-2026-63126?
CVE-2026-63126 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
What CWE is associated with CVE-2026-63126?
CVE-2026-63126 is classified under CWE-190: Integer Overflow or Wraparound (The product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. This occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may become a very small or negative number.).
How can I check Maven dependencies for CVE-2026-63126?
Run the dependency tree command: 'mvn dependency:tree -Dincludes=com.squareup.wire'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-9rm7-3qhh-h2mc",
  "modified" : "2026-09-17T14:52:52Z",
  "published" : "2026-09-17T14:52:52Z",
  "aliases" : [ "CVE-2026-63126" ],
  "summary" : "Wire: Unauthenticated decoder crash via 32-bit length integer overflow in ByteArrayProtoReader32 (incomplete fix of CVE-2026-45799)",
  "details" : "Wire's protobuf decoders did not consistently validate attacker-controlled length-delimited sizes against the current reader bounds before computing cursor, limit, or pointer positions.\n\nIn the Kotlin runtime, `ProtoAdapter.decode(ByteArray)` and `ProtoAdapter.decode(ByteString)` use the `ProtoReader32` fast path implemented by `ByteArrayProtoReader32`. In `ByteArrayProtoReader32.internalNextLengthDelimited()`, Wire read an untrusted varint length into an `Int` and rejected only negative values. A length such as `2147483647` is non-negative, so it passed that check, but `pos + length` overflowed the signed 32-bit cursor and produced a negative `limit`. The following `if (limit > pushedLimit)` guard did not catch this because the overflowed value was negative.\n\nThat invalid limit then reached string, bytes, skip, and scalar-reading paths as an invalid byte count or invalid range. Instead of failing as a checked decode error such as `IOException`, malformed input could throw unchecked runtime exceptions including `IllegalArgumentException` and `ArrayIndexOutOfBoundsException`. Applications commonly treat malformed protobuf input as an expected decode failure; unchecked runtime exceptions escaping that boundary can crash request handling or the process.\n\nThe original report is a sibling of the negative-length skipped-group bug fixed as CVE-2026-45799. It is not the same bug. The length in this advisory is positive, and the overflow occurs when setting a length-delimited message limit, not only when skipping a group.\n\nWhile auditing for the same bug class, related boundary flaws were also found and fixed:\n\n- Kotlin `ProtoReader` now validates logical message limits before varint, fixed32, fixed64, and skip operations. The originally reported byte-array overflow payload did not reproduce as the same signed overflow in `ProtoReader`, because that reader tracks positions as `Long`, but the streaming reader still needed consistent current-message-limit enforcement.\n- Swift `ReadBuffer.readVarint()` read `pointer.pointee` before checking that one byte remained. A tag-only varint field could read past the end of the buffer.\n- Swift `ReadBuffer.verifyAdditional(count:)` formed `pointer.advanced(by: count)` before proving the requested `count` fit within the remaining buffer, so pointer arithmetic ran before the bounds were established. (The distinct Swift negative-length `skipGroup()` crash is tracked separately as GHSA-86wm-r4c5-2rc9 / CVE-2026-61695; this advisory covers the positive/oversized-length boundary failures.)\n- Swift nested-message decoding and packed-repeated decoding computed end pointers from untrusted lengths before validating that the bytes were present.\n- Swift packed-repeated decoding reserved array capacity from an untrusted length before validating that the length existed in the current buffer.\n- Swift size-delimited decoding converted an untrusted `UInt64` varint size to `Int` without exactness or availability checks. On platforms where the value is not representable, this could trap.\n\nThe fix enforces a single invariant across the hardened readers: every decoded or skipped byte count must be non-negative and no larger than the remaining bytes in the current logical message limit before any cursor, pointer, limit, allocation, or slice is advanced.\n\n### Impact\n\nAn attacker who can supply protobuf bytes to an application using affected Wire decoders can trigger a denial of service by causing decode to fail with unchecked runtime failures or traps rather than normal malformed-input decode errors.\n\nKnown impact:\n\n- Availability impact only.\n- No known confidentiality impact.\n- No known integrity impact.\n- No known code execution.\n\nAttack requirements:\n\n- The application decodes attacker-controlled protobuf bytes with Wire.\n- No authentication is required if the decoding endpoint is reachable without authentication.\n- A single short malformed protobuf payload is sufficient for the Kotlin byte-array fast path.\n\nMost directly affected Kotlin entry points:\n\n- `ProtoAdapter.decode(ByteArray)`\n- `ProtoAdapter.decode(ByteString)`\n\nAdjacent Kotlin path hardened by this fix:\n\n- `ProtoAdapter.decode(BufferedSource)`\n- direct use of `ProtoReader`\n\nAffected Swift entry points:\n\n- Swift `ProtoDecoder` and `ProtoReader` APIs when decoding attacker-controlled `Data` or buffers.\n\n### Proof of concept and regression payloads\n\nThese payloads are intentionally small and should be treated as malformed protobuf input. After the fix, they must fail with normal decode errors such as `IOException`, `EOFException`, or `ProtoDecoder.Error.unexpectedEndOfData`, not unchecked runtime exceptions, traps, out-of-bounds reads, or large allocations.\n\n#### Kotlin byte-array known length-delimited field\n\nHex:\n\n```text\n0A FF FF FF FF 07\n```\n\nMeaning:\n\n- `0A`: field 1, length-delimited\n- `FF FF FF FF 07`: varint length `2147483647`\n\nPre-fix behavior observed through `Person.ADAPTER.decode(byteArray)`:\n\n```text\njava.lang.IllegalArgumentException: startIndex: 6 > endIndex: -2147483643\n```\n\nExpected fixed behavior:\n\n```text\nIOException / EOFException\n```\n\n#### Kotlin byte-array unknown length-delimited field\n\nHex:\n\n```text\n1A FF FF FF FF 07\n```\n\nMeaning:\n\n- `1A`: field 3, length-delimited\n- `FF FF FF FF 07`: varint length `2147483647`\n\nPre-fix behavior observed:\n\n```text\nArrayIndexOutOfBoundsException\n```\n\nExpected fixed behavior:\n\n```text\nIOException / EOFException\n```\n\n#### Kotlin byte-array skipped group containing oversized positive length\n\nHex:\n\n```text\n0B 0A FF FF FF FF 07 0C\n```\n\nMeaning:\n\n- `0B`: start group, field 1\n- `0A`: nested field 1, length-delimited\n- `FF FF FF FF 07`: varint length `2147483647`\n- `0C`: end group, field 1\n\nExpected fixed behavior:\n\n```text\nIOException / EOFException\n```\n\n#### Kotlin current-message-limit fixed32 boundary\n\nHex:\n\n```text\n02 0D 05 00 00 00\n```\n\nMeaning:\n\n- `02`: outer length-delimited message length is 2 bytes\n- `0D`: nested field 1, fixed32\n- `05 00 00 00`: enough bytes remain in the underlying source, but not inside the current logical message limit\n\nExpected fixed behavior:\n\n```text\nEOFException\n```\n\nThis covers the invariant that scalar reads must not cross the current length-delimited message boundary even when the underlying source has more bytes available.\n\n#### Swift tag-only varint value\n\nHex:\n\n```text\n08\n```\n\nMeaning:\n\n- `08`: field 1, varint\n- Missing varint value byte\n\nPre-fix risk:\n\n- `ReadBuffer.readVarint()` could dereference `pointer.pointee` before verifying that a byte remained.\n\nExpected fixed behavior:\n\n```text\nProtoDecoder.Error.unexpectedEndOfData\n```\n\n#### Swift nested message with oversized positive length\n\nHex:\n\n```text\n12 FF FF FF FF 07\n```\n\nMeaning:\n\n- `12`: field 2, length-delimited\n- `FF FF FF FF 07`: varint length `2147483647`\n\nPre-fix risk:\n\n- Nested message decoding computed an end pointer from an untrusted length before proving that the buffer contained that many bytes.\n\nExpected fixed behavior:\n\n```text\nProtoDecoder.Error.unexpectedEndOfData\n```\n\n#### Swift packed repeated field with oversized positive length\n\nHex:\n\n```text\n0A FF FF FF FF 07\n```\n\nMeaning:\n\n- `0A`: field 1, length-delimited packed repeated field\n- `FF FF FF FF 07`: varint length `2147483647`\n\nPre-fix risk:\n\n- Packed repeated decoding could reserve capacity based on an untrusted length before proving the bytes were present.\n\nExpected fixed behavior:\n\n```text\nProtoDecoder.Error.unexpectedEndOfData\n```\n\n#### Swift size-delimited stream with unrepresentable size\n\nHex:\n\n```text\nFF FF FF FF FF FF FF FF FF 01\n```\n\nMeaning:\n\n- Size-delimited message length varint `UInt64.max`\n\nPre-fix risk:\n\n- `ProtoDecoder.decodeSizeDelimited(_:from:)` converted the untrusted `UInt64` to `Int` without exactness checking.\n\nExpected fixed behavior:\n\n```text\nProtoDecoder.Error.unexpectedEndOfData\n```\n\n### Root cause\n\nThe vulnerable code mixed three operations that must remain separate:\n\n1. Decode an untrusted protobuf length.\n2. Validate that the length is non-negative and fits within the current logical message boundary.\n3. Advance the cursor, pointer, limit, slice, or allocation based on that length.\n\nIn the vulnerable paths, step 3 happened before step 2 was complete. For Kotlin `ByteArrayProtoReader32`, this caused signed integer wraparound in `pos + length`. For Swift, related pointer and allocation operations could be performed before proving the requested bytes existed.\n\n### Fix\n\nThe fix centralizes checked cursor and pointer advancement.\n\nKotlin changes:\n\n- `ByteArrayProtoReader32` now validates constructor invariants for `pos` and `limit`.\n- `ByteArrayProtoReader32` now uses shared helpers to:\n  - reject negative lengths,\n  - compute checked limits,\n  - compute remaining bytes in the current logical limit,\n  - validate before `skip`,\n  - validate before string and bytes reads,\n  - validate before fixed32 and fixed64 reads.\n- `ProtoReader` now mirrors the same logical-boundary model for:\n  - length-delimited limit calculation,\n  - skipped length-delimited fields,\n  - varint reads,\n  - fixed32 reads,\n  - fixed64 reads,\n  - current-message remaining-byte calculations.\n\nSwift changes:\n\n- `ReadBuffer` now computes checked end pointers only after confirming `count >= 0` and `count <= remaining`.\n- `ReadBuffer.readVarint()` verifies one byte remains before each byte dereference.\n- `ReadBuffer.readBuffer(count:)`, `readData(count:)`, `readFixed32()`, and `readFixed64()` compute the checked new pointer before reading and advancing.\n- `ProtoReader.beginMessage()` validates nested message lengths before storing a message-end pointer.\n- Packed repeated decoding validates the packed field length before preallocation and before constructing the loop boundary.\n- `ProtoDecoder.decodeSizeDelimited(_:from:)` converts sizes with `Int(exactly:)` and verifies that the full message bytes exist before constructing a child buffer.\n\nFixed in PR #3635:\n\n- https://github.com/square/wire/pull/3635\n- Fix commit `25ebcabb9ab7f12d1d77af75ecbc51726fddc015`\n\n### Workarounds\n\nThe recommended remediation is to upgrade to a patched release.\n\nPartial mitigations if an immediate upgrade is not possible:\n\n- Reject or cap untrusted protobuf message sizes before passing bytes to Wire.\n- Prefer decoding from a bounded source where possible rather than decoding unbounded attacker-controlled byte arrays.\n- Treat unchecked runtime exceptions from protobuf decode as malformed-input failures at service trust boundaries so they cannot crash the process.\n- For Swift, do not pass untrusted size-delimited streams or `Data` directly to affected decoders without an outer size cap and exception/error boundary.\n\nThese mitigations reduce exposure but do not fully fix the parser bugs.\n\n### Detection\n\nA crash or error may contain one of the following symptoms when processing malformed protobuf bytes:\n\n```text\nIllegalArgumentException: startIndex: 6 > endIndex: -2147483643\nArrayIndexOutOfBoundsException\nIndexOutOfBoundsException\nunexpected unchecked RuntimeException during ProtoAdapter.decode(ByteArray)\nSwift trap during Int conversion from an untrusted protobuf size\nSwift unexpected pointer/buffer failure while reading malformed varints or length-delimited values\n```\n\nThe absence of these exact messages does not prove safety. Any unchecked exception, trap, or process crash while decoding malformed length-delimited protobuf input should be investigated.\n\n### Verification\n\nRegression tests added:\n\n- `ProtoReader32Test.lengthDelimitedRejectsPositiveLengthOverflow`\n- `ProtoReader32Test.fixed32CannotReadPastLengthDelimitedLimit`\n- `ProtoReaderTest.fixed32CannotReadPastLengthDelimitedLimit`\n- `ProtoReaderTests.testReadVarintRejectsMissingValue`\n- `ProtoReaderTests.testNestedMessageRejectsOversizedLength`\n- `ProtoReaderTests.testPackedRepeatedRejectsOversizedLengthBeforePreallocation`\n- `ProtoDecoderTests.testDecodeSizeDelimitedRejectsUnrepresentableSize`\n\nFocused verification command:\n\n```bash\n./gradlew :wire-runtime:jvmTest :wire-runtime-swift:test\n```\n\nExpected result:\n\n```text\nBUILD SUCCESSFUL\n```\n\n### Relationship to related advisories\n\nThis is a distinct vulnerability from the negative-length issues. It is a\ndifferent bug class — a positive, non-negative length (for example\n`2147483647`) that passes the existing `length < 0` check but still overflows\nthe signed 32-bit cursor or crosses the current message boundary — and it has\na separate fix (PR #3635, not the negative-length PRs).\n\n- `CVE-2026-45799` / `GHSA-7xpr-hc2w-34m9` fixed the original Kotlin/JVM\n  negative-length skipped-group crash (Wire `6.3.0`). The non-negative\n  overflow described here was not covered by that check and remained\n  exploitable through `6.4.4`.\n- `GHSA-86wm-r4c5-2rc9` / `CVE-2026-61695` covers the Swift negative-length\n  `skipGroup()` crash (PR #3616). The Swift hardening in this advisory\n  (PR #3635) instead addresses positive/oversized-length overflow, buffer\n  over-read, and unrepresentable-size conversions in the Swift readers.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "com.squareup.wire:wire-runtime"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "6.4.5"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 6.4.4"
    }
  }, {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "com.squareup.wire:wire-runtime"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "7.0.0-alpha01"
      }, {
        "fixed" : "7.0.0-alpha04"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/security/advisories/GHSA-9rm7-3qhh-h2mc"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-63126"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/pull/3635"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/commit/082d5d83cec57ef68f1dd7d3e3d1d641c1fb670f"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/commit/25ebcabb9ab7f12d1d77af75ecbc51726fddc015"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/square/wire"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/releases/tag/6.4.5"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/square/wire/releases/tag/7.0.0-alpha04"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-190" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-17T14:52:52Z",
    "nvd_published_at" : "2026-09-16T19:17:24Z"
  }
}