Every CVE Search/ Get API key

CVE-2026-106104

Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server

8.7 HighFix available

Quasar Framework is a framework for building high-performance Vue.js user interfaces. Prior to 2.23.3, Platform.parseSSR() passed an unbounded User-Agent request header to getMatch() in ui/src/plugins/platform/Platform.js, whose browser-detection expressions combined greedy captures with repeated unbounded scans. Platform belongs to autoInstalledPlugins, so this parsing occurs before routing for every SSR request. A crafted unauthenticated request containing repeated version tokens without a terminating Safari token causes super-linear backtracking and blocks the Node.js event loop, delaying every other SSR request. SPA, PWA, Electron, Cordova, Capacitor, browser-extension, and static-site-generation targets are not affected because they do not parse an attacker-controlled request header through this path. This issue is fixed in version 2.23.3.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.37%Up 0.1 points since Oct 7, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.7

Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server

Quasar Framework is a framework for building high-performance Vue.js user interfaces. Prior to 2.23.3, Platform.parseSSR() passed an unbounded User-Agent request header to getMatch() in ui/src/plugins/platform/Platform.js, whose browser-detection expressions combined greedy captures with repeated unbounded scans. Platform belongs to autoInstalledPlugins, so this parsing occurs before routing for every SSR request. A crafted unauthenticated request containing repeated version tokens without a terminating Safari token causes super-linear backtracking and blocks the Node.js event loop, delaying every other SSR request. SPA, PWA, Electron, Cordova, Capacitor, browser-extension, and static-site-generation targets are not affected because they do not parse an attacker-controlled request header through this path. This issue is fixed in version 2.23.3.

Record
CVE-2026-106104
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1333
Updated
2026-11-02
EUVDEUVD-2026-93569 8.7

Quasar Framework is a framework for building high-performance Vue.js user interfaces. Prior to 2.23.3, Platform.parseSSR() passed an unbounded User-Agent request header to getMatch() in ui/src/plugins/platform/Platform.js, whose browser-detection expressions combined greedy captures with repeated unbounded scans. Platform belongs to autoInstalledPlugins, so this parsing occurs before routing for every SSR request. A crafted unauthenticated request containing repeated version tokens without a terminating Safari token causes super-linear backtracking and blocks the Node.js event loop, delaying every other SSR request. SPA, PWA, Electron, Cordova, Capacitor, browser-extension, and static-site-generation targets are not affected because they do not parse an attacker-controlled request header through this path. This issue is fixed in version 2.23.3.

Record
EUVD-2026-93569
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-68jq-fhch-4xq4 8.7

Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server

Summary

One unauthenticated request with a crafted User-Agent stalls a Quasar SSR server for seconds.

Quasar auto-installs its Platform plugin on every server-side render, and Platform.parseSSR() feeds the raw, unbounded User-Agent request header into a chain of backtracking regular expressions in getMatch(). One of those patterns contains a greedy capture followed by two unbounded .* scans, so a crafted header costs time proportional to the cube of its length. An 8 KB User-Agent blocks the Node.js event loop for about 4.4 seconds, and a 16 KB one for about 35 seconds. During that time the server answers nobody, so a handful of tiny requests take an SSR site completely offline.

Details

Platform is in the autoInstalledPlugins array in ui/src/install-quasar.js, so it is installed unconditionally by app.use(Quasar, ...). The generated SSR entry (app-vite/templates/entry/app.js, called from app-vite/templates/entry/server-entry.js) runs that for every HTTP request, and it runs before routing, so requests to paths that do not exist are affected too. On the server the plugin takes the header verbatim (ui/src/plugins/platform/Platform.js):

Platform.parseSSR = ssrContext => {
  const ua =
    ssrContext.req.headers['user-agent'] ||
    ssrContext.req.headers['User-Agent'] ||
    ''

  return { ...client, userAgent: ua, is: getPlatform(ua) }
}

getPlatform() lowercases the string and passes it to getMatch() (ui/src/plugins/platform/Platform.js:23-45), which evaluates an ordered chain of exec() calls. The sixth alternative, at ui/src/plugins/platform/Platform.js:32-34, is the problem:

/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent)

([\w.]+) is greedy and unbounded, and it is followed by two unbounded .* scans. When the input contains webkit/, many version/ tokens, and no safari/, the pattern can only fail after the engine has tried every combination of "where ([\w.]+) stops" against "which version occurrence the first .* lands on" against "how far the second .* searches for safari". That is O(k * m * L) states, and none of the earlier alternatives short-circuit it because none of them match. The fifth alternative has the same shape.

Measured on the functions loaded verbatim out of ui/src/plugins/platform/Platform.js, cost grows by a factor of eight for every doubling of the header:

UA   3998 B  ->      554 ms
UA   7998 B  ->     4368 ms      fits nginx default large_client_header_buffers 8k
UA  15998 B  ->    34995 ms      fits Node.js default --max-http-header-size 16k

A same-length header of ordinary characters costs 0.1 ms, so this is the regex and not the length.

Client-side rendering is not affected: there getPlatform() only ever sees navigator.userAgent, which the attacker does not control. The problem is specific to the SSR path, where the string arrives from the network.

PoC

The vulnerable pattern ships in the published package. From node_modules/quasar/dist/quasar.server.prod.js of [email protected]:

function M(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||...
  ||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||...
I.parseSSR=e=>{let t=e.req.headers[`user-agent`]||e.req.headers[`User-Agent`]||``;
               return{...F,userAgent:t,is:P(t)}};

Build the header:

const k = 3200                       // filler that maximises the greedy capture
const m = 479                        // "version/" tokens for the first .* to land on
const ua = 'webkit/' + 'a'.repeat(k) + ' ' + 'version/1 '.repeat(m)   // 7998 bytes

Server used for the end to end run, which performs exactly the per-request work Quasar SSR performs, through the real published package:

import http from 'node:http'
import { Platform } from 'quasar'          // resolves to dist/quasar.server.prod.js

http.createServer((req, res) => {
  const platform =…
Record
GHSA-68jq-fhch-4xq4
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1333
Updated
2026-11-02
NVD 8.7

Quasar Framework is a framework for building high-performance Vue.js user interfaces. Prior to 2.23.3, Platform.parseSSR() passed an unbounded User-Agent request header to getMatch() in ui/src/plugins/platform/Platform.js, whose browser-detection expressions combined greedy captures with repeated unbounded scans. Platform belongs to autoInstalledPlugins, so this parsing occurs before routing for every SSR request. A crafted unauthenticated request containing repeated version tokens without a terminating Safari token causes super-linear backtracking and blocks the Node.js event loop, delaying every other SSR request. SPA, PWA, Electron, Cordova, Capacitor, browser-extension, and static-site-generation targets are not affected because they do not parse an attacker-controlled request header through this path. This issue is fixed in version 2.23.3.

Record
CVE-2026-106104
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Weakness
CWE-1333
Updated
2026-11-02
OSV 8.7

Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server

Quasar Framework is a framework for building high-performance Vue.js user interfaces. Prior to 2.23.3, Platform.parseSSR() passed an unbounded User-Agent request header to getMatch() in ui/src/plugins/platform/Platform.js, whose browser-detection expressions combined greedy captures with repeated unbounded scans. Platform belongs to autoInstalledPlugins, so this parsing occurs before routing for every SSR request. A crafted unauthenticated request containing repeated version tokens without a terminating Safari token causes super-linear backtracking and blocks the Node.js event loop, delaying every other SSR request. SPA, PWA, Electron, Cordova, Capacitor, browser-extension, and static-site-generation targets are not affected because they do not parse an attacker-controlled request header through this path. This issue is fixed in version 2.23.3.

Record
CVE-2026-106104
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1333
Updated
2026-11-02
OSVGHSA-68jq-fhch-4xq4 8.7

Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server

Summary

One unauthenticated request with a crafted User-Agent stalls a Quasar SSR server for seconds.

Quasar auto-installs its Platform plugin on every server-side render, and Platform.parseSSR() feeds the raw, unbounded User-Agent request header into a chain of backtracking regular expressions in getMatch(). One of those patterns contains a greedy capture followed by two unbounded .* scans, so a crafted header costs time proportional to the cube of its length. An 8 KB User-Agent blocks the Node.js event loop for about 4.4 seconds, and a 16 KB one for about 35 seconds. During that time the server answers nobody, so a handful of tiny requests take an SSR site completely offline.

Details

Platform is in the autoInstalledPlugins array in ui/src/install-quasar.js, so it is installed unconditionally by app.use(Quasar, ...). The generated SSR entry (app-vite/templates/entry/app.js, called from app-vite/templates/entry/server-entry.js) runs that for every HTTP request, and it runs before routing, so requests to paths that do not exist are affected too. On the server the plugin takes the header verbatim (ui/src/plugins/platform/Platform.js):

Platform.parseSSR = ssrContext => {
  const ua =
    ssrContext.req.headers['user-agent'] ||
    ssrContext.req.headers['User-Agent'] ||
    ''

  return { ...client, userAgent: ua, is: getPlatform(ua) }
}

getPlatform() lowercases the string and passes it to getMatch() (ui/src/plugins/platform/Platform.js:23-45), which evaluates an ordered chain of exec() calls. The sixth alternative, at ui/src/plugins/platform/Platform.js:32-34, is the problem:

/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent)

([\w.]+) is greedy and unbounded, and it is followed by two unbounded .* scans. When the input contains webkit/, many version/ tokens, and no safari/, the pattern can only fail after the engine has tried every combination of "where ([\w.]+) stops" against "which version occurrence the first .* lands on" against "how far the second .* searches for safari". That is O(k * m * L) states, and none of the earlier alternatives short-circuit it because none of them match. The fifth alternative has the same shape.

Measured on the functions loaded verbatim out of ui/src/plugins/platform/Platform.js, cost grows by a factor of eight for every doubling of the header:

UA   3998 B  ->      554 ms
UA   7998 B  ->     4368 ms      fits nginx default large_client_header_buffers 8k
UA  15998 B  ->    34995 ms      fits Node.js default --max-http-header-size 16k

A same-length header of ordinary characters costs 0.1 ms, so this is the regex and not the length.

Client-side rendering is not affected: there getPlatform() only ever sees navigator.userAgent, which the attacker does not control. The problem is specific to the SSR path, where the string arrives from the network.

PoC

The vulnerable pattern ships in the published package. From node_modules/quasar/dist/quasar.server.prod.js of [email protected]:

function M(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||...
  ||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||...
I.parseSSR=e=>{let t=e.req.headers[`user-agent`]||e.req.headers[`User-Agent`]||``;
               return{...F,userAgent:t,is:P(t)}};

Build the header:

const k = 3200                       // filler that maximises the greedy capture
const m = 479                        // "version/" tokens for the first .* to land on
const ua = 'webkit/' + 'a'.repeat(k) + ' ' + 'version/1 '.repeat(m)   // 7998 bytes

Server used for the end to end run, which performs exactly the per-request work Quasar SSR performs, through the real published package:

import http from 'node:http'
import { Platform } from 'quasar'          // resolves to dist/quasar.server.prod.js

http.createServer((req, res) => {
  const platform =…
Record
GHSA-68jq-fhch-4xq4
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1333
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
quasar
npm
through 2.23.2
2.23.3
quasar
npm
before 2.23.3
2.23.3

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-106104 is a high vulnerability (CVSS 8.7) in Quasarframework Quasar, published October 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.37%, the 31st percentile. Fixed in quasar 2.23.3.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open