Every CVE Search/ Get API key

CVE-2026-63460

Vendure: Unauthenticated ReDoS via `regex` filter on SQLite backends

7.5 HighFix available

Vendure is an open-source headless commerce platform. Prior to 3.6.5, the public Shop GraphQL API allows an unauthenticated caller to supply a catastrophically backtracking pattern through StringOperators.regex. packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts passes the raw pattern to the REGEXP implementation registered by packages/core/src/service/helpers/list-query-builder/list-query-builder.ts, and better-sqlite3 and sqljs evaluate it synchronously in the Node.js event loop. ShopProductsResolver.products is publicly reachable, so one nested-quantifier pattern can block request processing and make the storefront and admin API unavailable, while repeated requests can sustain denial of service. PostgreSQL and MySQL or MariaDB deployments do not execute this regular expression in the Node.js event loop. This issue is fixed in version 3.6.5.

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.61%Up 0.2 points since Sep 18, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

Vendure: Unauthenticated ReDoS via `regex` filter on SQLite backends

Vendure is an open-source headless commerce platform. Prior to 3.6.5, the public Shop GraphQL API allows an unauthenticated caller to supply a catastrophically backtracking pattern through StringOperators.regex. packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts passes the raw pattern to the REGEXP implementation registered by packages/core/src/service/helpers/list-query-builder/list-query-builder.ts, and better-sqlite3 and sqljs evaluate it synchronously in the Node.js event loop. ShopProductsResolver.products is publicly reachable, so one nested-quantifier pattern can block request processing and make the storefront and admin API unavailable, while repeated requests can sustain denial of service. PostgreSQL and MySQL or MariaDB deployments do not execute this regular expression in the Node.js event loop. This issue is fixed in version 3.6.5.

Record
CVE-2026-63460
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-1333
Updated
2026-11-02
EUVDEUVD-2026-81667 7.5

Vendure is an open-source headless commerce platform. Prior to 3.6.5, the public Shop GraphQL API allows an unauthenticated caller to supply a catastrophically backtracking pattern through StringOperators.regex. packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts passes the raw pattern to the REGEXP implementation registered by packages/core/src/service/helpers/list-query-builder/list-query-builder.ts, and better-sqlite3 and sqljs evaluate it synchronously in the Node.js event loop. ShopProductsResolver.products is publicly reachable, so one nested-quantifier pattern can block request processing and make the storefront and admin API unavailable, while repeated requests can sustain denial of service. PostgreSQL and MySQL or MariaDB deployments do not execute this regular expression in the Node.js event loop. This issue is fixed in version 3.6.5.

Record
EUVD-2026-81667
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-jgm3-qmp2-c4p7 7.5

Vendure: Unauthenticated ReDoS via `regex` filter on SQLite backends

Summary

[!IMPORTANT] Only instances running on the SQLite driver (better-sqlite3) are affected; SQLite is usually used in development/testing backend, so production deployments on PostgreSQL or MySQL/MariaDB are unaffected.

The StringOperators.regex filter exposed on the public Shop GraphQL API is evaluated inside the Node.js event loop via a synchronous SQLite user-defined function (UDF). Supplying a catastrophically backtracking pattern blocks the entire event loop, causing a complete denial of service with no authentication required.


Details

Vendure registers a JavaScript UDF so that SQLite can handle the REGEXP operator:

packages/core/src/service/helpers/list-query-builder/list-query-builder.ts lines 917–931

private registerSQLiteRegexpFunction() {
    const regexpFn = (pattern: string, value: string) => {
        const result = new RegExp(`${pattern}`, 'i').test(value);  // user-controlled pattern
        return result ? 1 : 0;
    };
    if (dbType === 'better-sqlite3') {
        driver.databaseConnection.function('regexp', regexpFn);
    }
    if (dbType === 'sqljs') {
        driver.databaseConnection.create_function('regexp', regexpFn);
    }
}

The pattern argument is the raw value of StringOperators.regex submitted by the caller. No length limit, timeout, or safe-regex validation is applied before constructing new RegExp(pattern).

packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts lines 321–325

case 'regex':
    return {
        clause: getRegexpClause(fieldName, argIndex, dbType),
        parameters: { [`arg${argIndex}`]: operand },  // operand = raw user input
    };

The products resolver in packages/core/src/api/resolvers/shop/shop-products.resolver.ts carries no @Allow decorator, and the access control strategy treats an empty permission set as publicly accessible:

packages/core/src/config/auth/default-entity-access-control-strategy.ts lines 49–52

async canAccess(ctx: RequestContext, permissions: Permission[]): Promise<boolean> {
    if (permissions.length === 0) {
        return true;   // no @Allow → public
    }
    ...
}

The three conditions together — user-controlled regex, synchronous JS UDF on the event loop, unauthenticated access — create a complete unauthenticated DoS path.

Affected database drivers: better-sqlite3, sqljs.
MySQL/MariaDB and PostgreSQL delegate the pattern to the database engine (those engines have their own exposure characteristics but do not block the Node.js event loop).


PoC

<img width="1610" height="458" alt="image" src="https://github.com/user-attachments/assets/327f3847-79d9-43e2-859e-47a753e61b2b" /> [poc.zip](https://github.com/user-attachments/files/28752976/poc.zip) [poc-redos.js](https://github.com/user-attachments/files/28753000/poc-redos.js)

Prerequisites: Node.js ≥ 18. No account, no server, no dependencies.

Step 1 — save the following as poc-redos.js:

// Exact code from list-query-builder.ts:918-919
const PATTERN = '(a+)+$';
const VALUE   = 'a'.repeat(28) + 'b';
console.log('[*] pattern:', PATTERN, '  value:', VALUE);
console.log('[*] Starting (server would be unresponsive from this point)...');
const start = Date.now();
const result = new RegExp(`${PATTERN}`, 'i').test(VALUE);
console.log('[+] elapsed:', Date.now() - start, 'ms  result:', result);

Step 2 — run it:

node poc-redos.js

Expected output (verified on Node.js v24.14.0):

[*] pattern: (a+)+$   value: aaaaaaaaaaaaaaaaaaaaaaaaaaaab
[*] Starting (server would be unresponsive from this point)...
[+] elapsed: 19755 ms  result: false

A 29-character input causes ~20 seconds of CPU spin. Inside a live Vendure server this same code runs synchronously in the SQLite UDF on the Node.js event loop — the process cannot handle any other request for the entire duration.

**Step 3 — GraphQL payload (against a running…

Record
GHSA-jgm3-qmp2-c4p7
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-1333
Updated
2026-11-02
NVD 7.5

Vendure is an open-source headless commerce platform. Prior to 3.6.5, the public Shop GraphQL API allows an unauthenticated caller to supply a catastrophically backtracking pattern through StringOperators.regex. packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts passes the raw pattern to the REGEXP implementation registered by packages/core/src/service/helpers/list-query-builder/list-query-builder.ts, and better-sqlite3 and sqljs evaluate it synchronously in the Node.js event loop. ShopProductsResolver.products is publicly reachable, so one nested-quantifier pattern can block request processing and make the storefront and admin API unavailable, while repeated requests can sustain denial of service. PostgreSQL and MySQL or MariaDB deployments do not execute this regular expression in the Node.js event loop. This issue is fixed in version 3.6.5.

Record
CVE-2026-63460
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-1333
Updated
2026-11-02
OSV 7.5

Vendure: Unauthenticated ReDoS via `regex` filter on SQLite backends

Vendure is an open-source headless commerce platform. Prior to 3.6.5, the public Shop GraphQL API allows an unauthenticated caller to supply a catastrophically backtracking pattern through StringOperators.regex. packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts passes the raw pattern to the REGEXP implementation registered by packages/core/src/service/helpers/list-query-builder/list-query-builder.ts, and better-sqlite3 and sqljs evaluate it synchronously in the Node.js event loop. ShopProductsResolver.products is publicly reachable, so one nested-quantifier pattern can block request processing and make the storefront and admin API unavailable, while repeated requests can sustain denial of service. PostgreSQL and MySQL or MariaDB deployments do not execute this regular expression in the Node.js event loop. This issue is fixed in version 3.6.5.

Record
CVE-2026-63460
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-1333
Updated
2026-11-02
OSVGHSA-jgm3-qmp2-c4p7 7.5

Vendure: Unauthenticated ReDoS via `regex` filter on SQLite backends

Summary

[!IMPORTANT] Only instances running on the SQLite driver (better-sqlite3) are affected; SQLite is usually used in development/testing backend, so production deployments on PostgreSQL or MySQL/MariaDB are unaffected.

The StringOperators.regex filter exposed on the public Shop GraphQL API is evaluated inside the Node.js event loop via a synchronous SQLite user-defined function (UDF). Supplying a catastrophically backtracking pattern blocks the entire event loop, causing a complete denial of service with no authentication required.


Details

Vendure registers a JavaScript UDF so that SQLite can handle the REGEXP operator:

packages/core/src/service/helpers/list-query-builder/list-query-builder.ts lines 917–931

private registerSQLiteRegexpFunction() {
    const regexpFn = (pattern: string, value: string) => {
        const result = new RegExp(`${pattern}`, 'i').test(value);  // user-controlled pattern
        return result ? 1 : 0;
    };
    if (dbType === 'better-sqlite3') {
        driver.databaseConnection.function('regexp', regexpFn);
    }
    if (dbType === 'sqljs') {
        driver.databaseConnection.create_function('regexp', regexpFn);
    }
}

The pattern argument is the raw value of StringOperators.regex submitted by the caller. No length limit, timeout, or safe-regex validation is applied before constructing new RegExp(pattern).

packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts lines 321–325

case 'regex':
    return {
        clause: getRegexpClause(fieldName, argIndex, dbType),
        parameters: { [`arg${argIndex}`]: operand },  // operand = raw user input
    };

The products resolver in packages/core/src/api/resolvers/shop/shop-products.resolver.ts carries no @Allow decorator, and the access control strategy treats an empty permission set as publicly accessible:

packages/core/src/config/auth/default-entity-access-control-strategy.ts lines 49–52

async canAccess(ctx: RequestContext, permissions: Permission[]): Promise<boolean> {
    if (permissions.length === 0) {
        return true;   // no @Allow → public
    }
    ...
}

The three conditions together — user-controlled regex, synchronous JS UDF on the event loop, unauthenticated access — create a complete unauthenticated DoS path.

Affected database drivers: better-sqlite3, sqljs.
MySQL/MariaDB and PostgreSQL delegate the pattern to the database engine (those engines have their own exposure characteristics but do not block the Node.js event loop).


PoC

<img width="1610" height="458" alt="image" src="https://github.com/user-attachments/assets/327f3847-79d9-43e2-859e-47a753e61b2b" /> [poc.zip](https://github.com/user-attachments/files/28752976/poc.zip) [poc-redos.js](https://github.com/user-attachments/files/28753000/poc-redos.js)

Prerequisites: Node.js ≥ 18. No account, no server, no dependencies.

Step 1 — save the following as poc-redos.js:

// Exact code from list-query-builder.ts:918-919
const PATTERN = '(a+)+$';
const VALUE   = 'a'.repeat(28) + 'b';
console.log('[*] pattern:', PATTERN, '  value:', VALUE);
console.log('[*] Starting (server would be unresponsive from this point)...');
const start = Date.now();
const result = new RegExp(`${PATTERN}`, 'i').test(VALUE);
console.log('[+] elapsed:', Date.now() - start, 'ms  result:', result);

Step 2 — run it:

node poc-redos.js

Expected output (verified on Node.js v24.14.0):

[*] pattern: (a+)+$   value: aaaaaaaaaaaaaaaaaaaaaaaaaaaab
[*] Starting (server would be unresponsive from this point)...
[+] elapsed: 19755 ms  result: false

A 29-character input causes ~20 seconds of CPU spin. Inside a live Vendure server this same code runs synchronously in the SQLite UDF on the Node.js event loop — the process cannot handle any other request for the entire duration.

**Step 3 — GraphQL payload (against a running…

Record
GHSA-jgm3-qmp2-c4p7
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-1333
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
@vendure/core
npm
through 3.6.4
3.6.5
@vendure/core
npm
before 3.6.5
3.6.5

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-63460 is a high vulnerability (CVSS 7.5) in Vendurehq Vendure, published September 17, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.61%, the 49th percentile. Fixed in @vendure/core 3.6.5.

References

This page doesn't list everything

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

MoveEnter Open