GHSA-9wv6-86v2-598j

Suggest an improvement
Source
https://github.com/advisories/GHSA-9wv6-86v2-598j
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/09/GHSA-9wv6-86v2-598j/GHSA-9wv6-86v2-598j.json
JSON Data
https://api.test.osv.dev/v1/vulns/GHSA-9wv6-86v2-598j
Aliases
Related
Published
2024-09-09T20:19:15Z
Modified
2024-09-12T17:09:42Z
Severity
  • 7.5 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CVSS Calculator
  • 7.7 (High) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:P CVSS Calculator
Summary
path-to-regexp outputs backtracking regular expressions
Details

Impact

A bad regular expression is generated any time you have two parameters within a single segment, separated by something that is not a period (.). For example, /:a-:b.

Patches

For users of 0.1, upgrade to 0.1.10. All other users should upgrade to 8.0.0.

These versions add backtrack protection when a custom regex pattern is not provided:

They do not protect against vulnerable user supplied capture groups. Protecting against explicit user patterns is out of scope for old versions and not considered a vulnerability.

Version 7.1.0 can enable strict: true and get an error when the regular expression might be bad.

Version 8.0.0 removes the features that can cause a ReDoS.

Workarounds

All versions can be patched by providing a custom regular expression for parameters after the first in a single segment. As long as the custom regular expression does not match the text before the parameter, you will be safe. For example, change /:a-:b to /:a-:b([^-/]+).

If paths cannot be rewritten and versions cannot be upgraded, another alternative is to limit the URL length. For example, halving the attack string improves performance by 4x faster.

Details

Using /:a-:b will produce the regular expression /^\/([^\/]+?)-([^\/]+?)\/?$/. This can be exploited by a path such as /a${'-a'.repeat(8_000)}/a. OWASP has a good example of why this occurs, but the TL;DR is the /a at the end ensures this route would never match but due to naive backtracking it will still attempt every combination of the :a-:b on the repeated 8,000 -a.

Because JavaScript is single threaded and regex matching runs on the main thread, poor performance will block the event loop and can lead to a DoS. In local benchmarks, exploiting the unsafe regex will result in performance that is over 1000x worse than the safe regex. In a more realistic environment using Express v4 and 10 concurrent connections, this translated to average latency of ~600ms vs 1ms.

References

Database specific
{
    "nvd_published_at": "2024-09-09T19:15:13Z",
    "cwe_ids": [
        "CWE-1333"
    ],
    "severity": "HIGH",
    "github_reviewed": true,
    "github_reviewed_at": "2024-09-09T20:19:15Z"
}
References

Affected packages

npm / path-to-regexp

Package

Affected ranges

Type
SEMVER
Events
Introduced
0.2.0
Fixed
1.9.0

npm / path-to-regexp

Package

Affected ranges

Type
SEMVER
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
0.1.10

npm / path-to-regexp

Package

Affected ranges

Type
SEMVER
Events
Introduced
7.0.0
Fixed
8.0.0

npm / path-to-regexp

Package

Affected ranges

Type
SEMVER
Events
Introduced
2.0.0
Fixed
3.3.0

npm / path-to-regexp

Package

Affected ranges

Type
SEMVER
Events
Introduced
4.0.0
Fixed
6.3.0