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.


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-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.


References

Frequently Asked Questions

What is Denial of Service via malformed HTTP header decoding?

It is a vulnerability where an attacker sends a specially crafted HTTP header that the receiving application cannot safely parse, causing it to crash, loop indefinitely, or consume excessive resources—making the service unavailable to legitimate users.

How do you prevent Denial of Service via malformed header decoding in Node.js?

Always validate and sanitize incoming HTTP headers before passing them to parsing logic, use well-maintained libraries that are kept up to date, and apply input length and format checks at the edge (e.g., in middleware) before telemetry propagators ever see the raw header value.

What CWE is Denial of Service via malformed HTTP header decoding?

CWE-400 (Uncontrolled Resource Consumption), which covers cases where an application does not properly control the amount of resources it consumes in response to user-supplied input, enabling an attacker to exhaust those resources.

Is upgrading the package enough to prevent this vulnerability?

Yes, for CVE-2026-59892 the upgrade from 2.8.0 to 2.9.0 is the correct and complete fix. However, you should also ensure your dependency lock file (`package-lock.json`) is updated so that nested transitive dependencies (like `@opentelemetry/core`) are also resolved to their patched versions.

Can static analysis detect Denial of Service via malformed header decoding?

Yes. Tools like Trivy (which flagged this exact vulnerability) scan your dependency lock files against known CVE databases. Semgrep rules can also detect unsafe header-parsing patterns in source code before they reach production.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1613

Related Articles

critical

How server-side template injection happens in Node.js EJS and how to fix it

A critical server-side template injection vulnerability (CVE-2022-29078) was discovered in EJS version 3.1.6, allowing attackers to execute arbitrary code on the server through the `outputFunctionName` option. This vulnerability was fixed by upgrading EJS from 3.1.6 to 3.1.7 in the react-redux-bad-algo project, eliminating a dangerous remote code execution vector.

critical

How hardcoded API keys happen in Node.js client-side JavaScript and how to fix it

A critical hardcoded API key for ipregistry.co was discovered embedded as a fallback value in `src/utils.js` at line 65 of a Node.js library. This key (`f8n4kqe8pv4kii`) was visible to anyone inspecting the JavaScript bundle, allowing unauthorized use of the service. The fix removes the hardcoded fallback, requiring callers to explicitly provide their own API key.

critical

How unauthenticated API access happens in Node.js Express endpoints and how to fix it

The `/api/translate` endpoint in `api/translate.js` was publicly accessible without any authentication, allowing anonymous users to freely invoke paid Anthropic Claude or Google Translate API calls. This critical vulnerability exposed the application to API cost abuse, quota exhaustion, and potential data exfiltration. A targeted fix adds a shared-secret header check before any translation logic executes.

high

How HTTP Transport Hijacking via Prototype Pollution happens in Node.js axios and how to fix it

A high-severity vulnerability (CVE-2026-42033) in axios 1.13.6 allowed attackers to hijack HTTP transport behavior through prototype pollution, potentially redirecting sensitive requests to attacker-controlled servers. The fix upgrades axios to 1.15.1 and proxy-from-env to 2.1.0 in a Node.js sandbox base image used in production, eliminating the attack vector.

critical

How Denial of Service via gzip bomb happens in Node.js tar and how to fix it

A critical Denial of Service vulnerability (CVE-2026-59873) was discovered in the node-tar package where attackers could craft malicious gzip archives that expand to consume all available system resources. This vulnerability affected version 7.5.15 of the tar package and was fixed by upgrading to version 7.5.19. The fix protects applications from resource exhaustion attacks when processing untrusted archive files.

high

How Missing Dependabot Cooldown Periods Happen in GitHub Actions and How to Fix It

A critical security gap was discovered in the `.github/dependabot.yml` configuration file: the absence of cooldown periods for automated dependency updates. Without a 7-day grace period, Dependabot could automatically propose updates to newly published packages that might be malicious or unstable. The fix adds explicit `cooldown` blocks with `default-days: 7` to all package ecosystems.