Пример
path-to-regexp 8.4.2: Reject trailing backslash escape characters in route paths with a TypeError instead of silently parsing them as literal 'undefined'
Проверенный пример — npm path-to-regexp 8.4.2: Reject trailing backslash escape characters in route paths with a TypeError instead of silently parsing them…
sha256:93c74cb1f7ef74961b40b28dcf37f91c7be41470608867cd3c8919185eddf096
Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла.
Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди.
MIT-0
Свидетельства выполнения
Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.
- Основа свидетельства
- Подписанный контракт пройден
- Квитанции проверки
- 3
- Ключи подписи, собравшие его
- 3
Заявленная среда
node linux x64 node node npm
Среды запусков проверки
| Окружение | Контракт | Этапы | Запуск |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-16 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-07 |
Кейс
HOW- Цель
- Reject trailing backslash escape characters in route paths with a TypeError instead of silently parsing them as literal 'undefined'
- Пакеты
- Символы
-
- parse
- pathToRegexp
- match
- compile
- PathError
- Окружение
- node
- Создан
- 2026-08-16T06:21:57Z
Контракт
- parse('/test\\') throws TypeError (PathError) for unterminated trailing escape sequence
- pathToRegexp('/test\\') throws TypeError instead of compiling /^(?:\/testundefined)(?:\/$)?$/i
- match('/test\\') and compile('/test\\') throw TypeError on trailing backslash
- valid escape sequences such as '\:' preserve literal characters without error
Файлы
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
Исходный код
# Notes
## Search Results
`search_known_solution` returned low-confidence compatible alternative samples (`sha256:bb95306081deb0d7bdd735b0ca6f0182f77216c5d0426ee0146b7562efe7facc` for Express 5 route migration from Express 4, `sha256:2651162215727e626baac2f69d7b7e043707968fea0f9218aa9dda0648549e95` for Dart shelf routing, and `sha256:ec1c423e61b01693526ccce5e694e6c68ed968878f00b8331b3d82c953abea87` for Ecto changeset validation), with no sample addressing the trailing backslash parse bug or `path-to-regexp` v8.4.2 patch behavior.
## Naive Model Assumption
A model would assume that `pathToRegexp("/test\\")` either treats the trailing backslash as an escaped literal `\` character or matches the route `/test\`, without realizing that in `path-to-regexp <= 8.4.1` it out-of-bounds reads into `chars[index++]` and stringifies `undefined` into the path token as `/testundefined`.
## Failure Mode on Previous Version
On `path-to-regexp@8.4.1`, the contract fails loudly with `AssertionError: Missing expected exception (TypeError)` because `parse("/test\\")` and `pathToRegexp("/test\\")` silently succeed without throwing and compile into `/^(?:\/testundefined)(?:\/$)?$/i`.
{"case":{"caseId":"case:sha256:f945c0215967efd3a289c0be75696234736220073858d9c9eb079ad1bf146640","contract":["parse('/test\\\\') throws TypeError (PathError) for unterminated trailing escape sequence","pathToRegexp('/test\\\\') throws TypeError instead of compiling /^(?:\\/testundefined)(?:\\/$)?$/i","match('/test\\\\') and compile('/test\\\\') throw TypeError on trailing backslash","valid escape sequences such as '\\:' preserve literal characters without error"],"goal":"Reject trailing backslash escape characters in route paths with a TypeError instead of silently parsing them as literal 'undefined'","kind":"HOW","packages":["pkg:npm/path-to-regexp@8.4.2"],"schemaVersion":1,"symbols":["parse","pathToRegexp","match","compile","PathError"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/path-to-regexp@8.4.2"],"schemaVersion":1,"symbols":["parse","pathToRegexp","match","compile","PathError"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-path-to-regexp-bugfix",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-path-to-regexp-bugfix",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"path-to-regexp": "^8.4.2"
}
},
"node_modules/path-to-regexp": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
}
}
}
{
"name": "npm-path-to-regexp-bugfix",
"version": "1.0.0",
"private": true,
"type": "module",
"dependencies": {
"path-to-regexp": "8.4.2"
}
}
import assert from "node:assert/strict";
import { parse, pathToRegexp, match, compile, PathError } from "path-to-regexp";
// 1. In path-to-regexp <= 8.4.1, a trailing backslash was treated as an unescaped escape token,
// reading chars[index++] out of bounds and concatenating literal "undefined" to the token.
// In 8.4.2 (PR #434), parse() detects trailing backslash and throws TypeError (PathError).
assert.throws(
() => parse("/test\\"),
(err) => {
assert(err instanceof TypeError, "Expected err to be an instance of TypeError");
assert(err instanceof PathError, "Expected err to be an instance of PathError");
assert.match(err.message, /Unexpected end after \\ at index \d+/);
return true;
}
);
// 2. pathToRegexp on trailing backslash must throw TypeError rather than compiling /^(?:\/testundefined)(?:\/$)?$/i
assert.throws(
() => pathToRegexp("/test\\"),
(err) => {
assert(err instanceof TypeError, "Expected err to be an instance of TypeError");
assert(err instanceof PathError, "Expected err to be an instance of PathError");
return true;
}
);
// 3. match and compile on trailing backslash must throw TypeError
assert.throws(
() => match("/test\\"),
(err) => {
assert(err instanceof TypeError, "Expected err to be an instance of TypeError");
assert(err instanceof PathError, "Expected err to be an instance of PathError");
return true;
}
);
assert.throws(
() => compile("/test\\"),
(err) => {
assert(err instanceof TypeError, "Expected err to be an instance of TypeError");
assert(err instanceof PathError, "Expected err to be an instance of PathError");
return true;
}
);
// 4. Trailing escape inside nested route groups must also throw TypeError
assert.throws(
() => parse("/prefix{/test\\}"),
(err) => {
assert(err instanceof TypeError, "Expected err to be an instance of TypeError");
return true;
}
);
// 5. Valid escape sequences must continue to work properly without corruption
const parsed = parse("/test\\:id");
assert.deepStrictEqual(parsed.tokens, [{ type: "text", value: "/test:id" }]);
const fn = match("/test\\:id");
const matched = fn("/test:id");
assert.notStrictEqual(matched, false);
assert.strictEqual(matched.path, "/test:id");
assert.deepStrictEqual(matched.params, Object.create(null));
const toPath = compile("/test\\:id");
assert.strictEqual(toPath({}), "/test:id");