Skip to main content
Vulnerability Database/CVE-2026-84994

CVE-2026-84994: Qwik Framework DOS Vulnerability

CVE-2026-84994 is a denial of service vulnerability in Qwik JavaScript framework that allows attackers to crash servers through malicious JSON deserialization. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-84994 Overview

CVE-2026-84994 affects Qwik, a performance-focused JavaScript framework used for server-side rendered web applications. The vulnerability resides in the default server-side qwik-json deserialization logic, where ResourceSerializer.$fill$ passes resource._resolved to Promise.resolve without rejecting attacker-controlled thenables. An unauthenticated attacker can submit a plain object whose then property is a QRL (Qwik URL) referencing an unregistered symbol. The resulting orphaned asynchronous rejection terminates Node.js under its default unhandled-rejection policy. A single request crashes the server, and repeated requests keep replicas unavailable. The issue is fixed in @builder.io/qwik 1.20.0 and @qwik.dev/core 2.0.0-beta.37.

Critical Impact

An unauthenticated remote attacker can crash Qwik server replicas with a single HTTP request, producing a sustained denial-of-service condition.

Affected Products

  • @builder.io/qwik prior to 1.20.0
  • @qwik.dev/core prior to 2.0.0-beta.37
  • Qwik server-side rendering deployments running on Node.js with default unhandled-rejection policy

Discovery Timeline

  • 2026-10-13 - CVE-2026-84994 published to NVD
  • 2026-10-14 - Last updated in NVD database

Technical Details for CVE-2026-84994

Vulnerability Analysis

Qwik serializes server state into a qwik-json payload that is deserialized during resumability. The ResourceSerializer.$fill$ routine reconstructs resource objects by invoking Promise.resolve(resource._resolved). Because Promise.resolve adopts the state of any thenable passed to it, an attacker-supplied then function executes within the promise chain.

When the attacker-supplied then is a QRL pointing at an unregistered symbol, QRL resolution throws. The rejection has no attached handler, producing an unhandled promise rejection. Node.js terminates the process under its default --unhandled-rejections=throw policy, mapped to the Uncaught Exception weakness [CWE-248].

Root Cause

The deserializer trusted structural properties of the incoming JSON. It did not distinguish genuine Promise instances from attacker-crafted plain objects with a then property. Qwik also failed to attach a .catch handler to the resource promise, so any rejection became orphaned at the event loop level.

Attack Vector

The attack requires only an unauthenticated HTTP request to a Qwik-rendered endpoint that deserializes a qwik-json payload. The attacker supplies a JSON structure where a serialized resource contains a _resolved field shaped as a thenable whose then resolves to a QRL for an unregistered symbol.

typescript
   };
 }
 
+const createHandledRejectedPromise = (error: unknown) => {
+  const promise = Promise.reject(error);
+  promise.catch(() => null);
+  return promise;
+};
+
+const isThenable = (value: unknown) => {
+  if ((typeof value !== 'object' && typeof value !== 'function') || value === null) {
+    return false;
+  }
+  try {
+    return typeof (value as PromiseLike<unknown>).then === 'function';
+  } catch {
+    return true;
+  }
+};
+
 const QRLSerializer = /*#__PURE__*/ serializer<QRLInternal>({
   $prefix$: '\\u0002',
   $test$: (v) => isQrl(v),

Source: GitHub Commit c1e7444

The patch introduces an isThenable guard and a createHandledRejectedPromise helper. The resource serializer now detects attacker-controlled thenables and attaches a .catch handler so rejections cannot escape to the global unhandled-rejection path.

Detection Methods for CVE-2026-84994

Indicators of Compromise

  • Repeated Node.js process exits with messages matching UnhandledPromiseRejection originating from serializers.ts or ResourceSerializer.
  • Short-lived container or pod restarts correlated with inbound POST or GET requests to Qwik SSR endpoints.
  • HTTP request bodies containing qwik-json payloads with _resolved properties shaped as objects containing a then field.

Detection Strategies

  • Instrument Node.js with process.on('unhandledRejection') logging to capture stack traces before termination for forensic review.
  • Alert on orchestrator events, such as Kubernetes BackOff or CrashLoopBackOff, affecting Qwik SSR workloads.
  • Inspect reverse-proxy access logs for unusual payload sizes or malformed JSON directed at Qwik rendering routes.

Monitoring Recommendations

  • Track process uptime and restart frequency per replica; sudden drops indicate active exploitation.
  • Monitor the ratio of 5xx responses and connection resets from Qwik-fronted services.
  • Forward Node.js stderr containing rejection traces into a centralized log platform for correlation with request IDs.

How to Mitigate CVE-2026-84994

Immediate Actions Required

  • Upgrade @builder.io/qwik to 1.20.0 or @qwik.dev/core to 2.0.0-beta.37 across all production and staging environments.
  • Audit CI/CD lockfiles to confirm no transitive dependencies pin a vulnerable Qwik version.
  • Rate-limit unauthenticated requests to Qwik SSR endpoints while patching is in progress.

Patch Information

The fix is tracked in GitHub Pull Request #8655 and committed as c1e7444. Full release notes are available in the GitHub Release v1.20.0 and the GitHub Security Advisory GHSA-x586-xvc8-g7q6.

Workarounds

  • Run Node.js with --unhandled-rejections=warn as a temporary measure to prevent process termination, accepting the operational trade-off of silenced rejections.
  • Deploy a WAF rule that blocks request bodies containing qwik-json structures with a then property inside _resolved fields.
  • Place Qwik replicas behind an auto-restart supervisor combined with aggressive per-IP rate limiting until the upgrade is deployed.
bash
# Upgrade Qwik to the patched release
npm install @builder.io/qwik@1.20.0
# or for the next-generation package
npm install @qwik.dev/core@2.0.0-beta.37

# Verify the installed version
npm ls @builder.io/qwik

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.