CVE-2026-23886
Description
Swift W3C TraceContext is a Swift implementation of the W3C Trace Context standard, and Swift OTel is an OpenTelemetry Protocol (OTLP) backend for Swift Log, Swift Metrics, and Swift Distributed Tracing. Prior to Swift W3C TraceContext version 1.0.0-beta.5 and Swift OTel version 1.0.4, a denial-of-service vulnerability due to improper input validation allows a remote attacker to crash the service via a malformed HTTP header. This allows crashing the process with data coming from the network when used with, for example, an HTTP server. Most common way of using Swift W3C Trace Context is through Swift OTel. Version 1.0.0-beta.5 of Swift W3C TraceContext and version 1.0.4 of Swift OTel contain a patch for this issue. As a workaround, disable either Swift OTel or the code that extracts the trace information from an incoming header (such as a TracingMiddleware).
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/swift-otel/swift-w3c-trace-contextSwiftURL | < 1.0.0-beta.5 | 1.0.0-beta.5 |
github.com/swift-otel/swift-otelSwiftURL | < 1.0.4 | 1.0.4 |
Affected products
1- Range: 0.1.0, 0.2.0, 0.3.0, …
Patches
15da9b143ba60Merge commit from fork
3 files changed · +43 −9
Sources/W3CTraceContext/Hex.swift+3 −3 modified@@ -30,7 +30,7 @@ enum Hex { static func convert<T>( _ ascii: T, toBytes target: UnsafeMutableRawBufferPointer - ) where T: RandomAccessCollection, T.Element == UInt8 { + ) throws where T: RandomAccessCollection, T.Element == UInt8 { assert(ascii.count / 2 == target.count, "Target needs half as much space as ascii") var source = ascii.makeIterator() @@ -45,7 +45,7 @@ enum Hex { case UInt8(ascii: "a") ... UInt8(ascii: "f"): byte = (major - UInt8(ascii: "a") + 10) << 4 default: - preconditionFailure() + throw TraceParentDecodingError(.invalidCharacter(major)) } switch minor { @@ -54,7 +54,7 @@ enum Hex { case UInt8(ascii: "a") ... UInt8(ascii: "f"): byte |= (minor - UInt8(ascii: "a") + 10) default: - preconditionFailure() + throw TraceParentDecodingError(.invalidCharacter(minor)) } target[targetIndex] = byte
Sources/W3CTraceContext/TraceContext.swift+7 −6 modified@@ -69,8 +69,8 @@ public struct TraceContext: Sendable { // trace ID var traceIDBytes = TraceID.Bytes.null - withUnsafeMutableBytes(of: &traceIDBytes) { ptr in - Hex.convert(traceParent[3 ..< 35], toBytes: ptr) + try withUnsafeMutableBytes(of: &traceIDBytes) { ptr in + try Hex.convert(traceParent[3 ..< 35], toBytes: ptr) } if traceIDBytes == .null { throw TraceParentDecodingError( @@ -81,8 +81,8 @@ public struct TraceContext: Sendable { // span ID var spanIDBytes = SpanID.Bytes.null - spanIDBytes.withUnsafeMutableBytes { ptr in - Hex.convert(traceParent[36 ..< 52], toBytes: ptr) + try spanIDBytes.withUnsafeMutableBytes { ptr in + try Hex.convert(traceParent[36 ..< 52], toBytes: ptr) } if spanIDBytes == .null { throw TraceParentDecodingError( @@ -93,8 +93,8 @@ public struct TraceContext: Sendable { // flags var traceFlagsRawValue: UInt8 = 0 - withUnsafeMutableBytes(of: &traceFlagsRawValue) { ptr in - Hex.convert(traceParent[53 ..< 55], toBytes: ptr) + try withUnsafeMutableBytes(of: &traceFlagsRawValue) { ptr in + try Hex.convert(traceParent[53 ..< 55], toBytes: ptr) } let flags = TraceFlags(rawValue: traceFlagsRawValue) @@ -147,6 +147,7 @@ public struct TraceParentDecodingError: Error { case invalidTraceParentLength(Int) case unsupportedVersion(String) case invalidDelimiters + case invalidCharacter(UInt8) case invalidTraceID(String) case invalidSpanID(String) }
Tests/W3CTraceContextTests/TraceContextTests.swift+33 −0 modified@@ -46,6 +46,39 @@ final class TraceContextTests: XCTestCase { )) } + func test_decodingHeaderValues_withInvalidCharacterInTraceID_throwsDecodingError() throws { + do { + let traceContext = try TraceContext( + traceParentHeaderValue: "00-0Af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" + ) + XCTFail("Expected decoding error, decoded trace context: \(traceContext)") + } catch let error as TraceParentDecodingError { + XCTAssertEqual(error.reason, .invalidCharacter(UInt8(ascii: "A"))) + } + } + + func test_decodingHeaderValues_withInvalidCharacterInSpanID_throwsDecodingError() throws { + do { + let traceContext = try TraceContext( + traceParentHeaderValue: "00-0af7651916cd43dd8448eb211c80319c-B7ad6b7169203331-01" + ) + XCTFail("Expected decoding error, decoded trace context: \(traceContext)") + } catch let error as TraceParentDecodingError { + XCTAssertEqual(error.reason, .invalidCharacter(UInt8(ascii: "B"))) + } + } + + func test_decodingHeaderValues_withInvalidCharacterInFlags_throwsDecodingError() throws { + do { + let traceContext = try TraceContext( + traceParentHeaderValue: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-0C" + ) + XCTFail("Expected decoding error, decoded trace context: \(traceContext)") + } catch let error as TraceParentDecodingError { + XCTAssertEqual(error.reason, .invalidCharacter(UInt8(ascii: "C"))) + } + } + func test_decodingHeaderValues_withInvalidLength_throwsDecodingError() throws { do { let traceContext = try TraceContext(traceParentHeaderValue: String(repeating: "🏎️", count: 100))
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-mvpq-2v8x-ww6gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-23886ghsaADVISORY
- github.com/swift-otel/swift-otel/releases/tag/1.0.4nvdWEB
- github.com/swift-otel/swift-w3c-trace-context/commit/5da9b143ba6046734de3fa51dafea28290174e4envdWEB
- github.com/swift-otel/swift-w3c-trace-context/releases/tag/1.0.0-beta.5nvdWEB
- github.com/swift-otel/swift-w3c-trace-context/security/advisories/GHSA-mvpq-2v8x-ww6gnvdWEB
News mentions
0No linked articles in our index yet.