Back to Blog
high SEVERITY9 min read

How Denial of Service via malformed HTTP header decoding happens in Node.js @opentelemetry/propagator-jaeger and how to fix it

CVE-2026-59892 is a high-severity Denial of Service vulnerability in `@opentelemetry/propagator-jaeger` versions prior to 2.9.0, where malformed HTTP trace-context headers could cause the propagator's decoding logic to crash a Node.js application. The fix upgrades the package from 2.8.0 to 2.9.0, patching the unsafe header parsing behavior and eliminating the attack surface for any service that propagates distributed tracing headers.

O
By Orbis AppSec
Published July 30, 2026Reviewed July 30, 2026

Answer Summary

CVE-2026-59892 is a Denial of Service (CWE-400) vulnerability in the `@opentelemetry/propagator-jaeger` npm package (Node.js) affecting version 2.8.0 and earlier. Attackers can craft malformed Jaeger HTTP trace-context headers that cause the propagator's decoding logic to throw an unhandled error, crashing or hanging the receiving service. The fix is to upgrade `@opentelemetry/propagator-jaeger` from 2.8.0 to 2.9.0 (and its internal dependency `@opentelemetry/core` from 2.8.0 to 2.9.0), which hardens the header-parsing code against malformed input.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade `@opentelemetry/propagator-jaeger` to 2.9.0, which includes hardened header-decoding logic in the updated `@opentelemetry/core` 2.9.0 dependency
riskAttackers can crash or hang any Node.js service that uses Jaeger trace-context propagation by sending a single malformed HTTP header
languageJavaScript / Node.js
root cause`@opentelemetry/propagator-jaeger` 2.8.0 did not safely validate/parse incoming Jaeger trace headers before processing them, allowing malformed input to trigger an unhandled error
vulnerabilityDenial of Service via malformed HTTP header decoding

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/core 2.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:

  1. Crash the process if the error propagates to the top-level event loop
  2. Hang the request if the parsing enters an unexpected code path that never resolves the async chain
  3. 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.


Key Takeaways

  • @opentelemetry/propagator-jaeger 2.8.0 processes uber-trace-id headers 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/core dependency 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 just package-lock.json) prevents future npm install runs from silently reverting to a vulnerable version.
  • Trivy's lockfile scanning caught this before it became an incident—scanning package-lock.json for CVEs, not just package.json, is essential because transitive and nested dependencies are invisible to manifest-only scanners.

How Orbis AppSec Detected This

  • Source: The uber-trace-id HTTP header on any inbound request to the application—fully attacker-controlled, requiring no authentication.
  • Sink: The header decoding logic inside @opentelemetry/propagator-jaeger 2.8.0's extract() method, which delegates to string-parsing utilities in @opentelemetry/core 2.8.0 without sufficient input validation.
  • Missing control: No length or character-set validation was performed on the individual segments of the uber-trace-id header value before they were processed as trace and span IDs.
  • CWE: CWE-400 — Uncontrolled Resource Consumption
  • Fix: Upgraded @opentelemetry/propagator-jaeger from 2.8.0 to 2.9.0 in both package.json and package-lock.json, including a pinned nested resolution of @opentelemetry/core at 2.9.0 to 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.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1613

Related Articles

critical

deleteNestedProperty Prototype Pollution via Dot-Notation Path

The `deleteNestedProperty` function in propertyUtils.ts allowed attackers to manipulate JavaScript object prototypes by passing specially crafted dot-notation paths like `__proto__.polluted`. A fix now blocks dangerous keys before processing, preventing prototype pollution attacks that could affect all objects in the application.

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.