CVE-2025-12758
Description
Versions of the package validator before 13.15.22 are vulnerable to Incomplete Filtering of One or More Instances of Special Elements in the isLength() function that does not take into account Unicode variation selectors (\uFE0F, \uFE0E) appearing in a sequence which lead to improper string length calculation. This can lead to an application using isLength for input validation accepting strings significantly longer than intended, resulting in issues like data truncation in databases, buffer overflows in other system components, or denial-of-service.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
validatornpm | < 13.15.22 | 13.15.22 |
Affected products
1- Range: 0
Patches
1d457ecaf55b0fix(isLength): correctly handle Unicode variation selectors (#2616)
3 files changed · +145 −98
src/lib/isLength.js+1 −1 modified@@ -14,7 +14,7 @@ export default function isLength(str, options) { max = arguments[2]; } - const presentationSequences = str.match(/(\uFE0F|\uFE0E)/g) || []; + const presentationSequences = str.match(/[^\uFE0F\uFE0E][\uFE0F\uFE0E]/g) || []; const surrogatePairs = str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g) || []; const len = str.length - presentationSequences.length - surrogatePairs.length; const isInsideRange = len >= min && (typeof max === 'undefined' || len <= max);
test/validators/isLength.test.js+144 −0 added@@ -0,0 +1,144 @@ +import test from '../testFunctions'; + +describe('isLength', () => { + it('should return false for a string with length greater than the max', () => { + test({ + validator: 'isLength', + args: [{ max: 3 }], + invalid: ['test'], + }); + }); + + it('should return true for a string with length equal to the max', () => { + test({ + validator: 'isLength', + args: [{ max: 4 }], + valid: ['test'], + }); + }); + + it('should correctly calculate the length of a string with presentation sequences', () => { + test({ + validator: 'isLength', + args: [{ max: 4 }], + valid: ['test\uFE0F'], + }); + + test({ + validator: 'isLength', + args: [{ min: 5, max: 5 }], + valid: ['test\uFE0F\uFE0F'], + }); + + test({ + validator: 'isLength', + args: [{ min: 5, max: 5 }], + valid: ['\uFE0Ftest'], + }); + + test({ + validator: 'isLength', + args: [{ min: 9, max: 9 }], + valid: ['test\uFE0F\uFE0F\uFE0F\uFE0F\uFE0F\uFE0F'], + }); + }); + + it('should validate strings by length (deprecated api)', () => { + test({ + validator: 'isLength', + args: [2], + valid: ['abc', 'de', 'abcd'], + invalid: ['', 'a'], + }); + test({ + validator: 'isLength', + args: [2, 3], + valid: ['abc', 'de'], + invalid: ['', 'a', 'abcd'], + }); + test({ + validator: 'isLength', + args: [2, 3], + valid: ['干𩸽', '𠮷野家'], + invalid: ['', '𠀋', '千竈通り'], + }); + test({ + validator: 'isLength', + args: [0, 0], + valid: [''], + invalid: ['a', 'ab'], + }); + }); + + it('should validate strings by length', () => { + test({ + validator: 'isLength', + args: [{ min: 2 }], + valid: ['abc', 'de', 'abcd'], + invalid: ['', 'a'], + }); + test({ + validator: 'isLength', + args: [{ min: 2, max: 3 }], + valid: ['abc', 'de'], + invalid: ['', 'a', 'abcd'], + }); + test({ + validator: 'isLength', + args: [{ min: 2, max: 3 }], + valid: ['干𩸽', '𠮷野家'], + invalid: ['', '𠀋', '千竈通り'], + }); + test({ + validator: 'isLength', + args: [{ max: 3 }], + valid: ['abc', 'de', 'a', ''], + invalid: ['abcd'], + }); + test({ + validator: 'isLength', + args: [{ max: 6, discreteLengths: 5 }], + valid: ['abcd', 'vfd', 'ff', '', 'k'], + invalid: ['abcdefgh', 'hfjdksks'], + }); + test({ + validator: 'isLength', + args: [{ min: 2, max: 6, discreteLengths: 5 }], + valid: ['bsa', 'vfvd', 'ff'], + invalid: ['', ' ', 'hfskdunvc'], + }); + test({ + validator: 'isLength', + args: [{ min: 1, discreteLengths: 2 }], + valid: [' ', 'hello', 'bsa'], + invalid: [''], + }); + test({ + validator: 'isLength', + args: [{ max: 0 }], + valid: [''], + invalid: ['a', 'ab'], + }); + test({ + validator: 'isLength', + args: [{ min: 5, max: 10, discreteLengths: [2, 6, 8, 9] }], + valid: ['helloguy', 'shopping', 'validator', 'length'], + invalid: ['abcde', 'abcdefg'], + }); + test({ + validator: 'isLength', + args: [{ discreteLengths: '9' }], + valid: ['a', 'abcd', 'abcdefghijkl'], + invalid: [], + }); + test({ + validator: 'isLength', + valid: ['a', '', 'asds'], + }); + test({ + validator: 'isLength', + args: [{ max: 8 }], + valid: ['👩🦰👩👩👦👦🏳️🌈', '⏩︎⏩︎⏪︎⏪︎⏭︎⏭︎⏮︎⏮︎'], + }); + }); +});
test/validators.test.js+0 −97 modified@@ -5591,32 +5591,6 @@ describe('Validators', () => { }); }); - it('should validate strings by length (deprecated api)', () => { - test({ - validator: 'isLength', - args: [2], - valid: ['abc', 'de', 'abcd'], - invalid: ['', 'a'], - }); - test({ - validator: 'isLength', - args: [2, 3], - valid: ['abc', 'de'], - invalid: ['', 'a', 'abcd'], - }); - test({ - validator: 'isLength', - args: [2, 3], - valid: ['干𩸽', '𠮷野家'], - invalid: ['', '𠀋', '千竈通り'], - }); - test({ - validator: 'isLength', - args: [0, 0], - valid: [''], - invalid: ['a', 'ab'], - }); - }); it('should validate isLocale codes', () => { test({ @@ -5695,77 +5669,6 @@ describe('Validators', () => { }); }); - it('should validate strings by length', () => { - test({ - validator: 'isLength', - args: [{ min: 2 }], - valid: ['abc', 'de', 'abcd'], - invalid: ['', 'a'], - }); - test({ - validator: 'isLength', - args: [{ min: 2, max: 3 }], - valid: ['abc', 'de'], - invalid: ['', 'a', 'abcd'], - }); - test({ - validator: 'isLength', - args: [{ min: 2, max: 3 }], - valid: ['干𩸽', '𠮷野家'], - invalid: ['', '𠀋', '千竈通り'], - }); - test({ - validator: 'isLength', - args: [{ max: 3 }], - valid: ['abc', 'de', 'a', ''], - invalid: ['abcd'], - }); - test({ - validator: 'isLength', - args: [{ max: 6, discreteLengths: 5 }], - valid: ['abcd', 'vfd', 'ff', '', 'k'], - invalid: ['abcdefgh', 'hfjdksks'], - }); - test({ - validator: 'isLength', - args: [{ min: 2, max: 6, discreteLengths: 5 }], - valid: ['bsa', 'vfvd', 'ff'], - invalid: ['', ' ', 'hfskdunvc'], - }); - test({ - validator: 'isLength', - args: [{ min: 1, discreteLengths: 2 }], - valid: [' ', 'hello', 'bsa'], - invalid: [''], - }); - test({ - validator: 'isLength', - args: [{ max: 0 }], - valid: [''], - invalid: ['a', 'ab'], - }); - test({ - validator: 'isLength', - args: [{ min: 5, max: 10, discreteLengths: [2, 6, 8, 9] }], - valid: ['helloguy', 'shopping', 'validator', 'length'], - invalid: ['abcde', 'abcdefg'], - }); - test({ - validator: 'isLength', - args: [{ discreteLengths: '9' }], - valid: ['a', 'abcd', 'abcdefghijkl'], - invalid: [], - }); - test({ - validator: 'isLength', - valid: ['a', '', 'asds'], - }); - test({ - validator: 'isLength', - args: [{ max: 8 }], - valid: ['👩🦰👩👩👦👦🏳️🌈', '⏩︎⏩︎⏪︎⏪︎⏭︎⏭︎⏮︎⏮︎'], - }); - }); it('should validate strings by byte length', () => { test({
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-vghf-hv5q-vc2gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-12758ghsaADVISORY
- seclists.org/fulldisclosure/2026/Jan/27ghsaWEB
- gist.github.com/koral--/ad31208b25b9e3d1e2e35f1d4d72572eghsaWEB
- github.com/validatorjs/validator.js/commit/d457ecaf55b0f3d8bd379d82757425d0d13dd382ghsaWEB
- github.com/validatorjs/validator.js/pull/2616ghsaWEB
- security.snyk.io/vuln/SNYK-JS-VALIDATOR-13653476ghsaWEB
News mentions
0No linked articles in our index yet.