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
path-to-regexp version: 8.4.1 (latest)
- Node.js: v20+
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:
- Silently fail to match any legitimate requests to that path
- 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
Summary
When a path string ends with a backslash (
\), theparse()function produces a token with the literal string"undefined"appended to its value. This causespathToRegexp()to generate a regex that matches the wrong path entirely.Environment
path-to-regexpversion: 8.4.1 (latest)Reproduction
Root Cause
In
parse(), the escape token handler does:When
\is the last character in the string,chars[index++]reads past the end of the array and returnsundefined. JavaScript then coerces this to the string"undefined"when it is concatenated inconsumeUntil()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:
undefinedliterally appendedThis 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:
Expected Behavior
parse()should throw aPathErrorwhen a backslash appears as the last character (unterminated escape), similar to how unterminated quotes are handled:Suggested Fix
Discovered via manual source code audit of v8.4.1. No exploit code released.
Reported by Travis Burmaster — travis@burmaster.com