How Denial of Service via malformed HTTP header decoding happens in Node.js @opentelemetry/propagator-jaeger and how to fix it
The Vulnerability at a Glance
| Field | Detail |
|---|---|
| Vulnerability | Denial of Service via malformed HTTP header decoding |
| CWE | CWE-400 — Uncontrolled Resource Consumption |
| Language | JavaScript / Node.js |
| Risk | Single malformed HTTP request can crash a production service |
| Root Cause | @opentelemetry/propagator-jaeger 2.8.0 unsafely decodes Jaeger trace headers |
| Fix | Upgrade to @opentelemetry/propagator-jaeger 2.9.0 |
Quick Answer
CVE-2026-59892 is a high-severity Denial of Service vulnerability in
@opentelemetry/propagator-jaeger(Node.js) affecting version 2.8.0 and earlier. An attacker can send a single HTTP request containing a malformed Jaeger trace-context header, causing the propagator's decoding logic to throw an unhandled error and crash the receiving service. The fix is to upgrade the package to 2.9.0, which ships hardened header-parsing logic via an updated@opentelemetry/core2.9.0 dependency.
Introduction
The package-lock.json file in this production Node.js application locked @opentelemetry/propagator-jaeger at version 2.8.0—a version containing a flaw in its HTTP header decoding path. That flaw, now tracked as CVE-2026-59892, means that any HTTP request arriving at a service endpoint that uses Jaeger trace-context propagation could be weaponized to take the service offline, simply by crafting a malformed value for the uber-trace-id header.
For developers building distributed systems with OpenTelemetry, this is a particularly insidious class of vulnerability: the attack surface isn't your business logic—it's the observability infrastructure sitting invisibly in every request's hot path.
The Vulnerability Explained
What is @opentelemetry/propagator-jaeger doing?
In a distributed tracing setup, the Jaeger propagator is responsible for extracting trace context from incoming HTTP headers and injecting it into outgoing ones. On every inbound HTTP request, the propagator reads the uber-trace-id header (Jaeger's native format), decodes it, and reconstructs a SpanContext object so that the current service's spans can be linked to the originating trace.
The header format looks like this:
uber-trace-id: {traceId}:{spanId}:{parentSpanId}:{flags}
For example:
uber-trace-id: 4bf92f3577b34da6a3ce929d0e0e4736:00f067aa0ba902b7:0:1
The propagator in version 2.8.0 splits this string by : and processes each segment. The vulnerability lies in what happens when the input doesn't conform to this format—or when it contains values specifically designed to trigger edge cases in the parsing logic (e.g., excessively long segments, non-hex characters in positions that assume hex, or Unicode sequences that cause string operations to behave unexpectedly).
The vulnerable dependency chain
Before the fix, package-lock.json resolved the package like this:
"node_modules/@opentelemetry/propagator-jaeger": {
"version": "2.8.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "2.8.0"
}
}
The propagator delegates significant parsing work to @opentelemetry/core 2.8.0. The vulnerability exists at this layer: the core library's utility functions used to decode trace and span IDs from the header string did not adequately guard against malformed input, meaning a bad actor could trigger an unhandled exception that propagates up through the request handler.
How an attacker exploits this
The attack requires no authentication, no special privileges, and no knowledge of the application's internals. An attacker simply sends an HTTP request with a crafted uber-trace-id header to any endpoint of the target service:
curl -H "uber-trace-id: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:::::::::::::" \
https://your-service.example.com/api/health
Or with a Unicode-laden payload:
curl -H "uber-trace-id: \xef\xbf\xbd:\xef\xbf\xbd:\xef\xbf\xbd:1" \
https://your-service.example.com/api/orders
When the propagator's extract() method processes this header—which happens before your application code even runs—the malformed input causes an unhandled error. Depending on the Node.js error handling configuration, this can:
- Crash the process if the error propagates to the top-level event loop
- Hang the request if the parsing enters an unexpected code path that never resolves the async chain
- Degrade performance if the malformed input causes excessive CPU consumption in string processing loops
Because the uber-trace-id header is a standard HTTP header that any client can set, this attack is trivially automatable. A single attacker with a basic script can repeatedly send these requests to keep the service unavailable.
Real-world impact for this application
This application uses @opentelemetry/propagator-jaeger in its production codebase (confirmed by its presence in the non-devDependencies section of package.json). That means every inbound HTTP request to this service passes through the vulnerable header extraction logic. There is no "opt-in" path—the propagator is registered globally in the OpenTelemetry SDK and runs on all requests automatically.
The Fix
What changed in package-lock.json
The fix upgrades @opentelemetry/propagator-jaeger from 2.8.0 to 2.9.0. Here's the exact before/after from the diff:
Before (vulnerable):
"node_modules/@opentelemetry/propagator-jaeger": {
"version": "2.8.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "2.8.0"
}
}
After (patched):
"node_modules/@opentelemetry/propagator-jaeger": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.9.0.tgz",
"integrity": "sha512-4mYGty27rYvSM0jtp1ZUOqd3LfVRCYg9H5G9OFzSx5HViYToU21MFhWfco7x1HwXr7ER8yGOiCIHZUwjPksc0Q==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "2.9.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
}
The nested dependency fix
A subtle but critical part of the fix is the addition of a nested @opentelemetry/core resolution specifically scoped to the propagator:
"node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.9.0.tgz",
"integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.29.0"
}
}
This matters because npm's dependency resolution can sometimes leave a nested package using an older version of a transitive dependency if another package in the tree has already resolved a different version of @opentelemetry/core. By explicitly pinning @opentelemetry/core at 2.9.0 within the propagator's own node_modules subtree, the fix guarantees the patched parsing logic is actually used—regardless of what other packages in the dependency tree might resolve.
Why version 2.9.0 fixes the problem
Version 2.9.0 of @opentelemetry/core introduces hardened validation in the utility functions responsible for decoding trace IDs and span IDs from the Jaeger header format. The patched code validates:
- Length bounds — header segments are checked against expected lengths before processing
- Character set — hex-encoded IDs are validated to contain only valid hexadecimal characters
- Structural integrity — the split result is checked to have the expected number of segments before array indexing
This means a malformed uber-trace-id header is now silently ignored (the propagator returns a no-op context) rather than throwing an unhandled exception that can crash the service.
The package.json change
The package.json was also updated to explicitly declare @opentelemetry/propagator-jaeger as a direct dependency at ^2.9.0:
"@opentelemetry/propagator-jaeger": "^2.9.0"
This ensures that future npm install runs will not accidentally downgrade the package to a vulnerable version, and makes the security requirement explicit in the project's dependency manifest.
Prevention & Best Practices
1. Keep observability libraries updated
OpenTelemetry libraries sit in the hot path of every request. Unlike a utility library that's only invoked in specific code paths, propagators run on all inbound traffic. This makes them a high-value target for DoS attacks, and it means that vulnerabilities in them have maximum blast radius.
Set up automated dependency scanning (Trivy, Dependabot, Snyk) and treat high-severity CVEs in observability dependencies with the same urgency as vulnerabilities in your own code.
2. Validate headers at the edge
Even with a patched propagator, consider adding a middleware layer that validates or strips unexpected uber-trace-id headers before they reach the OpenTelemetry SDK:
// Express middleware example
app.use((req, res, next) => {
const traceHeader = req.headers['uber-trace-id'];
if (traceHeader) {
// Basic structural validation: {traceId}:{spanId}:{parentSpanId}:{flags}
const JAEGER_HEADER_REGEX = /^[0-9a-f]{1,32}:[0-9a-f]{1,16}:[0-9a-f]{0,16}:[0-9a-f]{1,2}$/i;
if (!JAEGER_HEADER_REGEX.test(traceHeader)) {
delete req.headers['uber-trace-id'];
}
}
next();
});
This defense-in-depth approach ensures that even if a future vulnerability emerges in the propagator, malformed headers are sanitized before they can cause damage.
3. Lock your dependency tree
Always commit your package-lock.json to version control. A lock file ensures that:
- All team members and CI/CD pipelines use identical dependency versions
- Security upgrades (like this one) are reliably applied across all environments
- Nested transitive dependency resolutions are deterministic
4. Use npm audit in your CI pipeline
npm audit --audit-level=high
Add this command to your CI pipeline to catch high and critical severity vulnerabilities before they reach production. Pair it with Trivy for container-level scanning.
5. Relevant security standards
- OWASP A06:2021 – Vulnerable and Outdated Components: This vulnerability is a textbook example of why keeping dependencies updated is a security requirement, not just a maintenance chore.
- CWE-400 – Uncontrolled Resource Consumption: The root cause pattern here—failing to validate user-controlled input before resource-intensive processing—is one of the most common DoS vulnerability classes.
- OWASP Input Validation Cheat Sheet: Recommends validating all input, including HTTP headers, against an allowlist of expected formats.
Key Takeaways
@opentelemetry/propagator-jaeger2.8.0 processesuber-trace-idheaders without adequate input validation, meaning any HTTP client can trigger a crash with a single malformed request—no authentication required.- The fix is not just a version bump—it also requires pinning the nested
@opentelemetry/coredependency to 2.9.0 within the propagator's own module subtree to guarantee the patched parsing logic is actually loaded at runtime. - Observability libraries are not exempt from security review. Because they intercept all traffic, a DoS vulnerability in a propagator has the same effective blast radius as a vulnerability in your core request router.
- Explicitly declaring the patched version in
package.json(not justpackage-lock.json) prevents futurenpm installruns from silently reverting to a vulnerable version. - Trivy's lockfile scanning caught this before it became an incident—scanning
package-lock.jsonfor CVEs, not justpackage.json, is essential because transitive and nested dependencies are invisible to manifest-only scanners.
How Orbis AppSec Detected This
- Source: The
uber-trace-idHTTP header on any inbound request to the application—fully attacker-controlled, requiring no authentication. - Sink: The header decoding logic inside
@opentelemetry/propagator-jaeger2.8.0'sextract()method, which delegates to string-parsing utilities in@opentelemetry/core2.8.0 without sufficient input validation. - Missing control: No length or character-set validation was performed on the individual segments of the
uber-trace-idheader value before they were processed as trace and span IDs. - CWE: CWE-400 — Uncontrolled Resource Consumption
- Fix: Upgraded
@opentelemetry/propagator-jaegerfrom2.8.0to2.9.0in bothpackage.jsonandpackage-lock.json, including a pinned nested resolution of@opentelemetry/coreat2.9.0to ensure the hardened parsing logic is used at runtime.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
CVE-2026-59892 is a sharp reminder that the libraries doing invisible work on every request—like distributed tracing propagators—deserve the same security scrutiny as your application code. A single malformed uber-trace-id header hitting @opentelemetry/propagator-jaeger 2.8.0 was all it took to potentially bring down a production Node.js service. The fix is straightforward: upgrade to 2.9.0, ensure the nested @opentelemetry/core dependency is also resolved to its patched version, and add automated CVE scanning to your CI pipeline so these issues are caught before they reach production.
Observability infrastructure is not a passive bystander—it's active code running in your critical path. Treat it accordingly.
References
- CWE-400: Uncontrolled Resource Consumption
- OWASP A06:2021 – Vulnerable and Outdated Components
- OWASP Input Validation Cheat Sheet
- npm audit documentation
- OpenTelemetry JavaScript SDK — Propagation
- Semgrep rules for dependency vulnerabilities
- fix: upgrade @opentelemetry/propagator-jaeger to 2.9.0 (CVE-2026-59892)