Bug: Trailing backslash in path injects literal "undefined" into token value (original) (raw)

Summary

When a path string ends with a backslash (\), the parse() function produces a token with the literal string "undefined" appended to its value. This causes pathToRegexp() to generate a regex that matches the wrong path entirely.

Environment

Reproduction

const { parse, pathToRegexp } = require("path-to-regexp");

// parse() produces "undefined" in token value console.log(parse("/test\").tokens); // => [{ type: "text", value: "/testundefined" }] ⚠️

// pathToRegexp() generates wrong regex const { regexp } = pathToRegexp("/test\"); console.log(regexp.toString()); // => /^(?:/testundefined)(?:/$)?$/i

// The route now matches the wrong path console.log(regexp.test("/testundefined")); // true ⚠️ console.log(regexp.test("/test")); // false ⚠️

Root Cause

In parse(), the escape token handler does:

else if (value === "\") { tokens.push({ type: "escape", index, value: chars[index++] }); }

When \ is the last character in the string, chars[index++] reads past the end of the array and returns undefined. JavaScript then coerces this to the string "undefined" when it is concatenated in consumeUntil() to build the text token value.

Impact

Any route defined with a trailing backslash (e.g. from user-supplied route definitions, config files, or programmatic path construction) will:

  1. Silently fail to match any legitimate requests to that path
  2. Instead match requests to the path with undefined literally appended

This can cause route confusion and potential security bypasses if middleware guards a route that is inadvertently broken by this bug.

Additionally, the same issue affects intermediate backslashes followed by end-of-string:

parse("/a\b\").tokens // => [{ type: "text", value: "/abundefined" }] ⚠️

Expected Behavior

parse() should throw a PathError when a backslash appears as the last character (unterminated escape), similar to how unterminated quotes are handled:

throw new PathError(Unterminated escape at index ${index}, str);

Suggested Fix

else if (value === "\") { if (index >= chars.length) { throw new PathError(Unterminated escape at index ${index - 1}, str); } tokens.push({ type: "escape", index, value: chars[index++] }); }


Discovered via manual source code audit of v8.4.1. No exploit code released.

Reported by Travis Burmaster — travis@burmaster.com