High severityNVD Advisory· Published Oct 26, 2024· Updated Apr 15, 2026
CVE-2020-26309
CVE-2020-26309
Description
Validate.js provides a declarative way of validating javascript objects. Versions 0.11.3 and prior contain one or more regular expressions that are vulnerable to Regular Expression Denial of Service (ReDoS). As of time of publication, it is unknown if any patches are available.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
nope-validatornpm | < 0.12.1 | 0.12.1 |
Patches
2c8af9f93abe8fix url regexp (#422)
2 files changed · +22 −15
src/consts.ts+1 −1 modified@@ -1,3 +1,3 @@ export const emailRegex = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; -export const urlRegex = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i; +export const urlRegex = /^([a-z][a-z0-9\*\-\.]*):\/\/(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*(?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@)?(?:(?:[a-z0-9\-\.]|%[0-9a-f]{2})+|(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]))(?::[0-9]+)?(?:[\/|\?](?:[\w#!:\.\?\+=&@!$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)?$/i;
src/__tests__/NopeString.spec.ts+21 −14 modified@@ -7,9 +7,7 @@ describe('#NopeString', () => { }); it('should return an error message for an invalid entry', () => { - expect(Nope.string().regex(/abc/i, 'errorMessage').validate('http:google.com')).toBe( - 'errorMessage', - ); + expect(Nope.string().regex(/abc/i, 'errorMessage').validate('defg')).toBe('errorMessage'); }); it('should return undefined for an valid entry', () => { @@ -23,20 +21,29 @@ describe('#NopeString', () => { }); it('should return an error message for an invalid URL', () => { - expect(Nope.string().url().validate('http:google.com')).toBe('Input is not a valid url'); + const invalidUrls = [ + 'http://:google.com', + 'http://', + // 'http:///a', + 'http://foo.bar/foo(bar)baz quux', + ]; + for (const url of invalidUrls) { + expect(Nope.string().url().validate(url)).toBe('Input is not a valid url'); + } }); it('should return undefined for an valid URL', () => { - expect(Nope.string().url('urlErrorMessage').validate('https://google.com')).toBe(undefined); - expect(Nope.string().url('urlErrorMessage').validate('https://google.com?asd=123')).toBe( - undefined, - ); - expect(Nope.string().url('urlErrorMessage').validate('https://google.com/123')).toBe( - undefined, - ); - expect(Nope.string().url('urlErrorMessage').validate('https://google.com/123/456?q=42')).toBe( - undefined, - ); + const validUrls = [ + 'https://github.com/bvego/nope-validator/commit/4564b7444dcd92769e5c5b80420469c9f18b7a05?branch=4564b7444dcd92769e5c5b80420469c9f18b7a05&diff=split', + 'https://google.com', + 'https://google.com?asd=123', + 'https://google.com/123', + 'https://google.com/123/456?q=42', + ]; + + for (const url of validUrls) { + expect(Nope.string().url('urlErrorMessage').validate(url)).toBe(undefined); + } }); });
4564b7444dcdUpdate email and url regex (#421)
2 files changed · +23 −8
src/consts.ts+2 −2 modified@@ -1,3 +1,3 @@ -export const emailRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; +export const emailRegex = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; -export const urlRegex = /^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; +export const urlRegex = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
src/__tests__/NopeString.spec.ts+21 −6 modified@@ -28,6 +28,15 @@ describe('#NopeString', () => { it('should return undefined for an valid URL', () => { expect(Nope.string().url('urlErrorMessage').validate('https://google.com')).toBe(undefined); + expect(Nope.string().url('urlErrorMessage').validate('https://google.com?asd=123')).toBe( + undefined, + ); + expect(Nope.string().url('urlErrorMessage').validate('https://google.com/123')).toBe( + undefined, + ); + expect(Nope.string().url('urlErrorMessage').validate('https://google.com/123/456?q=42')).toBe( + undefined, + ); }); }); @@ -37,15 +46,21 @@ describe('#NopeString', () => { }); it('should return an error message for an invalid email', () => { - expect(Nope.string().email().validate('bruno.vegogmail.com')).toBe( - 'Input is not a valid email', - ); + const ns = () => Nope.string(); + + const ERR_MSG = 'err'; + + expect(ns().email(ERR_MSG).validate('bruno.vegogmail.com')).toBe(ERR_MSG); + expect(ns().email(ERR_MSG).validate('bruno.vego.gmail.com')).toBe(ERR_MSG); + expect(ns().email(ERR_MSG).validate('bruno.vego@gmail.com@')).toBe(ERR_MSG); }); it('should return undefined for an valid email', () => { - expect(Nope.string().email('emailErrorMessage').validate('bruno.vego@gmail.com')).toBe( - undefined, - ); + const ns = () => Nope.string(); + + expect(ns().email().validate('bruno.vego@gmail.com')).toBe(undefined); + expect(ns().email().validate('random-guy@google.com')).toBe(undefined); + expect(ns().email().validate('random-guy+test@google.com')).toBe(undefined); }); });
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-3phv-83cj-p8p7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-26309ghsaADVISORY
- securitylab.github.com/advisories/GHSL-2020-303-redos-nope-validatorghsaADVISORY
- github.com/ftonato/nope-validator/commit/4564b7444dcd92769e5c5b80420469c9f18b7a05ghsaWEB
- github.com/ftonato/nope-validator/commit/c8af9f93abe8f4786f8f69d2b0518f8ca3652f44ghsaWEB
- github.com/ftonato/nope-validator/issues/352nvdWEB
- securitylab.github.com/advisories/GHSL-2020-303-redos-nope-validator/nvd
News mentions
0No linked articles in our index yet.