Apr 23, 2026·6 min read·136 visits
OpenTelemetry .NET SDK versions up to 1.15.2 are vulnerable to a Denial of Service (DoS) attack via unauthenticated memory exhaustion (CWE-789). Maliciously crafted propagation headers force eager memory allocations, causing high garbage collection pressure. Patch to version 1.15.3 to resolve the issue.
The OpenTelemetry .NET SDK contains a denial of service vulnerability due to excessive memory allocation during the parsing of propagation headers. Vulnerable versions utilize eager allocation strategies, specifically `string.Split()`, to process Baggage, B3, and Jaeger headers. Unauthenticated remote attackers can exploit this by submitting crafted headers containing dense sequences of delimiters, forcing the application to allocate thousands of objects per request. This results in severe garbage collection pressure and potential OutOfMemoryException conditions. The vulnerability is fixed in version 1.15.3.
The OpenTelemetry .NET SDK provides instrumentation for distributed tracing, metrics, and logging. A core component of distributed tracing is context propagation, which ensures trace IDs, span IDs, and custom metadata (Baggage) are passed across service boundaries. The SDK extracts this context from incoming HTTP requests by reading standard propagation headers, including Baggage, B3, and Jaeger headers.
CVE-2026-40894 describes an allocation amplification vulnerability within the header parsing logic of OpenTelemetry.Api and OpenTelemetry.Extensions.Propagators. The vulnerability is classified under CWE-789 (Memory Allocation with Excessive Size Value). When the SDK processes incoming propagation headers, it employs an eager allocation strategy that scales linearly with the number of delimiter characters present in the header string, regardless of the actual data content.
An attacker with network access to an exposed service running the vulnerable OpenTelemetry .NET SDK can trigger this vulnerability by sending HTTP requests with intentionally malformed context headers. Because context propagation operates early in the ASP.NET Core request pipeline—often before authentication or application-level routing—this vulnerability is exploitable without credentials and affects the entire application surface area.
The fundamental flaw lies in the BaggagePropagator, B3Propagator, and JaegerPropagator classes, which utilized string.Split() to separate key-value pairs and list items. This method parses the entire input string immediately, creating an intermediate array of strings and allocating memory for each resulting substring. This pattern occurs before the SDK validates the total length of the header or the number of items it contains.
In the .NET memory model, each string allocation incurs overhead. A header payload of 8,192 bytes consisting entirely of comma delimiters (,) will instruct string.Split(',') to allocate an array capable of holding 8,193 references, followed by the instantiation of 8,193 empty string objects on the managed heap. The memory consumed by these objects significantly exceeds the original 8-kilobyte footprint of the header string.
Furthermore, a logic flaw in BaggagePropagator.Inject<T>() bypassed the standard 8,192-character limit if the baggage collection contained exactly one item. This allowed an application processing a malicious payload to serialize and propagate an oversized header to downstream microservices. This cascading effect broadens the denial-of-service condition across the internal service mesh.
The unpatched implementation relied on framework methods that generated managed allocations per delimiter. The fix, introduced in PR #7061, fundamentally alters the string processing model by replacing string.Split with manual parsing utilizing ReadOnlySpan<char>. The use of Span<T> allows the SDK to view and traverse segments of the original header string without duplicating memory.
The updated B3Propagator utilizes a custom ReadNextPart function. This function iterates through the header string using pointer arithmetic conceptually, isolating segments of the string sequentially.
// Refactored logic in B3Propagator.cs introduced in v1.15.3
private static ReadOnlySpan<char> ReadNextPart(ReadOnlySpan<char> header, int position, out int nextPosition)
{
var remaining = header.Slice(position);
var separatorIndex = remaining.IndexOf(XB3CombinedDelimiter);
if (separatorIndex < 0)
{
nextPosition = header.Length;
return remaining;
}
var result = remaining.Slice(0, separatorIndex);
nextPosition = position + separatorIndex + 1;
return result;
}This refactored logic operates entirely without heap allocations. Slice and IndexOf execute quickly over the contiguous memory area of the original string. Additionally, the patch introduces strict limit enforcement during the iteration phase. The parser actively tracks the item count and halts processing immediately if the 180-item limit or the 8,192-character limit is exceeded, neutralizing the allocation amplification vector.
Exploitation of CVE-2026-40894 requires an attacker to repeatedly submit HTTP requests containing crafted headers. The payload consists of standard HTTP headers targeting the OpenTelemetry extraction keys, such as baggage or b3. The value of the header is constructed entirely of delimiter characters.
A single HTTP request carrying baggage: ,,,,,[...5000 commas...] triggers the immediate allocation of thousands of string objects in Generation 0 of the .NET Garbage Collector. While Gen 0 collections are fast, sustained concurrent requests rapidly exhaust Gen 0 capacity. This forces the runtime to promote objects to Generation 1 and Generation 2.
When Generation 2 collections are triggered frequently, the .NET runtime suspends application execution (a "stop-the-world" pause) to compact the heap. This CPU-intensive process blocks thread execution, resulting in severe latency degradation. If the incoming request rate exceeds the garbage collector's ability to free memory, the application will throw an OutOfMemoryException and terminate.
The patch cycle that resolved CVE-2026-40894 also addressed related resource management vulnerabilities in the SDK. In PR #7064, the GrpcStatusDeserializer within OpenTelemetry.Exporter.OpenTelemetryProtocol was modified. The deserializer previously trusted the length prefix (Varint) of incoming GRPC status messages, allocating byte arrays based on the attacker-controlled length value without verifying the actual stream length. This provided another avenue for uncontrolled memory allocation.
Additionally, PR #7069 addressed a resource leak in the background export workers (BatchExportTaskWorker and PeriodicExportingMetricReaderTaskWorker). In specific environments, such as Blazor WebAssembly, these workers leaked asynchronous tasks. This failure to release task resources resulted in linear memory growth over the lifetime of the application.
These combined findings indicate a systemic pattern of trust in external input lengths and suboptimal resource management in earlier versions of the SDK. The transition to Span-based processing and strict boundary validation in version 1.15.3 marks a critical architectural hardening against resource exhaustion attacks.
The primary remediation for CVE-2026-40894 is to update all dependencies on OpenTelemetry.Api and OpenTelemetry.Extensions.Propagators to version 1.15.3 or later. Developers must ensure that all transient dependencies are also updated, which may require explicit package references in the project file to force NuGet to resolve the patched version.
If immediate patching is not possible, organizations can apply mitigation controls at the ingress layer. Web Application Firewalls (WAF) or API Gateways can be configured to drop requests containing baggage, b3, or uber-trace-id headers that exceed a specific character length or contain an excessive number of delimiter characters. Limiting the length of these headers to 1,024 characters will effectively mitigate the denial-of-service vector without interrupting normal distributed tracing operations.
Organizations should monitor application memory metrics and garbage collection frequency. Sudden spikes in Gen 2 collections, coupled with high allocations of string arrays, indicate potential exploitation attempts. Analyzing incoming HTTP traffic for abnormally large or malformed tracing headers will confirm the presence of this attack vector.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenTelemetry.Api OpenTelemetry | >= 0.5.0-beta.2, <= 1.15.2 | 1.15.3 |
OpenTelemetry.Extensions.Propagators OpenTelemetry | >= 1.3.1, <= 1.15.2 | 1.15.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-789 |
| Attack Vector | Network |
| CVSS v3.1 | 5.3 |
| EPSS | N/A |
| Impact | Denial of Service (DoS) |
| Exploit Status | Proof of Concept |
| KEV Status | Not Listed |
Memory Allocation with Excessive Size Value
An unsigned 32-bit integer underflow vulnerability in the Windows Management Instrumentation (WMI) serialization subsystem of ntoskrnl.exe allows local authenticated users with low privileges to corrupt adjacent kernel pool allocations, execute arbitrary kernel-mode read and write operations, and perform a Token Swap attack to escalate their privileges to NT AUTHORITY\SYSTEM.
JupyterLab's PluginManager contains an authorization bypass vulnerability allowing authenticated users to modify the state of locked extensions or plugins. Although the frontend user interface visually locks and disables toggle components for administrative configurations, the backend API fails to perform robust validation. Standard users can craft direct HTTP API requests to modify plugin states, completely bypassing administrative restrictions.
GHSA-89VP-JRXV-24W8 is a security bypass vulnerability in the JupyterLab Extension Manager. Authenticated users can install unauthorized or blocklisted extension packages from PyPI. This bypass occurs due to improper canonicalization of package names and the incorrect synchronous invocation of an asynchronous permission-checking method.
A stored Cross-Site Scripting (XSS) vulnerability exists in JupyterLab's Image Viewer component when processing Scalable Vector Graphics (SVG) images. Due to the lingering lifecycle of generated object URLs and the inheritance of the application origin by client-side Blobs, an attacker can execute arbitrary JavaScript within the victim's active session. This execution occurs when a user views an SVG file in the JupyterLab image viewer, right-clicks the image, and selects 'Open image in new tab'.
JupyterLab versions 4.5.x and 4.6.x prior to 4.5.10 and 4.6.2 are vulnerable to a DOM-based Cross-Site Scripting (XSS) vulnerability. An attacker can craft a malicious overrides.json file that executes arbitrary JavaScript inside the victim's browser session. This can occur either automatically if the file is pre-planted on a multi-tenant filesystem, or via user interaction when importing settings.
A module-cache poisoning vulnerability exists in the n8n JavaScript task runner. In multi-tenant or multi-user n8n deployments, custom code executed inside Code nodes shares a single Node.js process and memory space. If custom module loading is enabled via configuration, an authorized user can dynamically patch (monkey-patch) globally cached modules. Subsequent executions of workflows by other tenants or users that load the same module will receive the poisoned reference, resulting in cross-tenant data exposure, credential hijacking, or integrity compromise.