Regular Expression Denial of Service (ReDoS)
Description
Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Lodash before 4.17.21 is vulnerable to ReDoS via toNumber, trim, and trimEnd due to catastrophic backtracking in regex patterns.
Lodash versions prior to 4.17.21 contain a Regular Expression Denial of Service (ReDoS) vulnerability in the toNumber, trim, and trimEnd functions. The root cause is the use of regex patterns like /^\s+|\s+$/g and /\s+$/ that can cause catastrophic backtracking when processing large, specially crafted input strings [1][2]. This behavior is characteristic of ReDoS, where an attacker can craft input that forces the regex engine to take exponential time to evaluate, leading to excessive CPU consumption and denial of service [4].
The attack is exploitable without authentication in many scenarios, as these functions are commonly used to sanitize user-supplied input. An attacker can send a relatively short string (e.g., a long sequence of spaces followed by specific characters) to trigger the slowdown. The vulnerability is particularly severe because it affects a widely used utility library across many applications and platforms, including Node.js and browser environments [1][4].
The impact is a denial of service condition: the application becomes unresponsive or crashes as the CPU is consumed by the regex backtracking. Since Lodash is often used in server-side and client-side code, this can affect availability for legitimate users. The CVSS score is 7.5 (high), reflecting the low attack complexity and potential for significant impact [1].
The vulnerability is fixed in Lodash version 4.17.21. Users should upgrade to this version or later. The fix, introduced in pull request #5065 and commit c4847eb, replaces the problematic regex patterns with more efficient algorithms: baseTrim and trimmedEndIndex functions that avoid catastrophic backtracking by using character checks instead of complex regex [2][3]. No workarounds are recommended; upgrading is the definitive mitigation.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
lodashnpm | >= 4.0.0, < 4.17.21 | 4.17.21 |
lodash-esnpm | >= 4.0.0, < 4.17.21 | 4.17.21 |
lodash.trimendnpm | >= 4.0.0, <= 4.5.1 | — |
lodash.trimnpm | >= 4.0.0, <= 4.5.1 | — |
lodash-railsRubyGems | >= 4.0.0, < 4.17.21 | 4.17.21 |
Affected products
6- Lodash/Lodashdescription
- ghsa-coords5 versions
>= 4.0.0, < 4.17.21+ 4 more
- (no CPE)range: >= 4.0.0, < 4.17.21
- (no CPE)range: >= 4.0.0, < 4.17.21
- (no CPE)range: >= 4.0.0, < 4.17.21
- (no CPE)range: >= 4.0.0, <= 4.5.1
- (no CPE)range: >= 4.0.0, <= 4.5.1
Patches
1c4847ebe7d14Improve performance of `toNumber`, `trim` and `trimEnd` on large input strings
2 files changed · +68 −7
lodash.js+36 −7 modified@@ -153,10 +153,11 @@ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source); - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; + /** Used to match leading whitespace. */ + var reTrimStart = /^\s+/; + + /** Used to match a single whitespace character. */ + var reWhitespace = /\s/; /** Used to match wrap detail comments. */ var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, @@ -1006,6 +1007,19 @@ }); } + /** + * The base implementation of `_.trim`. + * + * @private + * @param {string} string The string to trim. + * @returns {string} Returns the trimmed string. + */ + function baseTrim(string) { + return string + ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') + : string; + } + /** * The base implementation of `_.unary` without support for storing metadata. * @@ -1339,6 +1353,21 @@ : asciiToArray(string); } + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ + function trimmedEndIndex(string) { + var index = string.length; + + while (index-- && reWhitespace.test(string.charAt(index))) {} + return index; + } + /** * Used by `_.unescape` to convert HTML entities to characters. * @@ -12507,7 +12536,7 @@ if (typeof value != 'string') { return value === 0 ? value : +value; } - value = value.replace(reTrim, ''); + value = baseTrim(value); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) @@ -14998,7 +15027,7 @@ function trim(string, chars, guard) { string = toString(string); if (string && (guard || chars === undefined)) { - return string.replace(reTrim, ''); + return baseTrim(string); } if (!string || !(chars = baseToString(chars))) { return string; @@ -15033,7 +15062,7 @@ function trimEnd(string, chars, guard) { string = toString(string); if (string && (guard || chars === undefined)) { - return string.replace(reTrimEnd, ''); + return string.slice(0, trimmedEndIndex(string) + 1); } if (!string || !(chars = baseToString(chars))) { return string;
test/test.js+32 −0 modified@@ -23783,6 +23783,22 @@ assert.deepEqual(actual, expected); }); + + QUnit.test('`_.`' + methodName + '` should prevent ReDoS', function(assert) { + assert.expect(2); + + var largeStrLen = 50000, + largeStr = '1' + lodashStable.repeat(' ', largeStrLen) + '1', + maxMs = 1000, + startTime = lodashStable.now(); + + assert.deepEqual(_[methodName](largeStr), methodName == 'toNumber' ? NaN : 0); + + var endTime = lodashStable.now(), + timeSpent = endTime - startTime; + + assert.ok(timeSpent < maxMs, 'operation took ' + timeSpent + 'ms'); + }); }); /*--------------------------------------------------------------------------*/ @@ -24368,6 +24384,22 @@ assert.strictEqual(func(string, ''), string); }); + QUnit.test('`_.`' + methodName + '` should prevent ReDoS', function(assert) { + assert.expect(2); + + var largeStrLen = 50000, + largeStr = 'A' + lodashStable.repeat(' ', largeStrLen) + 'A', + maxMs = 1000, + startTime = lodashStable.now(); + + assert.strictEqual(_[methodName](largeStr), largeStr); + + var endTime = lodashStable.now(), + timeSpent = endTime - startTime; + + assert.ok(timeSpent < maxMs, 'operation took ' + timeSpent + 'ms'); + }); + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1);
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
21- github.com/advisories/GHSA-29mw-wpgm-hmr9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-28500ghsaADVISORY
- cert-portal.siemens.com/productcert/pdf/ssa-637483.pdfghsax_refsource_CONFIRMWEB
- github.com/github/advisory-database/pull/6139ghsaWEB
- github.com/lodash/lodash/blob/npm/trimEnd.js%23L8ghsax_refsource_MISCWEB
- github.com/lodash/lodash/commit/c4847ebe7d14540bb28a8b932a9ce1b9ecbfee1aghsaWEB
- github.com/lodash/lodash/pull/5065ghsax_refsource_MISCWEB
- github.com/lodash/lodash/pull/5065/commits/02906b8191d3c100c193fe6f7b27d1c40f200bb7ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/lodash-rails/CVE-2020-28500.ymlghsaWEB
- security.netapp.com/advisory/ntap-20210312-0006ghsaWEB
- security.netapp.com/advisory/ntap-20210312-0006/mitrex_refsource_CONFIRM
- snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074894ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074892ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074895ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074893ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-LODASH-1018905ghsax_refsource_MISCWEB
- www.oracle.com//security-alerts/cpujul2021.htmlghsax_refsource_MISCWEB
- www.oracle.com/security-alerts/cpujan2022.htmlghsax_refsource_MISCWEB
- www.oracle.com/security-alerts/cpujul2022.htmlghsax_refsource_MISCWEB
- www.oracle.com/security-alerts/cpuoct2021.htmlghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.