VULNARCHIVE

GCVE-1988-2026-0230

CVE-2025-12758: Unicode Variation Selectors Bypass in 'validator' library (isLength)

Description (en)

Summary
=======
A vulnerability was discovered in the popular JavaScript library
'validator'.
The isLength() function incorrectly handles Unicode Variation Selectors
(U+FE0E and U+FE0F). An attacker can inject thousands of these zero-width
characters into a string, causing the library to report a much smaller
perceived length than the actual byte size. This leads to validation
bypasses,
potential database truncation, and Denial of Service (DoS).

Metadata
========
CVE ID: CVE-2025-12758
Vulnerability Type: Incomplete Filtering of Special Elements (CWE-792)
Affected Package: validator (npm)
Affected Versions: < 13.15.22
Fixed Version: 13.15.22
CVSS Score: 7.5 (High) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H

Description
===========
The 'validator' library's isLength() method is widely used to enforce
constraints on input data. However, the implementation failed to account
for
Unicode Variation Selectors. These are zero-width code points that modify
the
presentation of the preceding character (e.g., changing a text character
into
an emoji).

Because these characters have zero width but occupy bytes in memory (UTF-16
surrogate pairs or single code points depending on the environment), an
attacker can craft a payload that:
1. Appears to have a length of 1 (e.g., 'a' followed by 5000 variation
selectors).
2. isLength() reports it as length 1 or 2 (depending on internal logic).
3. The actual memory/storage size is massive (e.g., 10,000+ bytes).

Impact
======
- Denial of Service (DoS): Sending extremely large payloads that pass
length
  checks can exhaust server memory or CPU during processing.
- Data Truncation: Databases with strict byte limits (e.g., VARCHAR(255))
  may truncate the string, potentially leading to data corruption or
  application logic errors.
- Security Bypass: Bypassing UI or API limits intended to prevent large
  blobs of data.

Proof of Concept (PoC)
======================
const validator = require('validator');

// 'a' followed by many Variation Selector-16 (\uFE0F)
const payload = 'a' + '\uFE0F'.repeat(5000);

console.log("Actual length (chars):", payload.length); // 5001
console.log("Validator isLength(payload, {max: 5}):",
            validator.isLength(payload, {max: 5}));

// In vulnerable versions, this returns 'true' because selectors
// were not properly counted or were ignored in a way that bypassed
// the total length check.

Fix
===
The issue was fixed in version 13.15.22 by implementing a surgical fix
that correctly identifies and counts valid Unicode pairs and variation
selectors, ensuring the reported length matches the actual data footprint
more accurately.

Timeline
========
- 2025-10-18: Vulnerability reported to maintainers by Karol Wrótniak.
- 2025-11-27: CVE-2025-12758 published.
- 2025-11-09: Fixed version 13.15.22 released.

References
==========
[1] https://www.thedroidsonroids.com/blog/when-zero-width-isnt-zero
[2] https://nvd.nist.gov/vuln/detail/CVE-2025-12758
[3] https://github.com/validatorjs/validator.js/releases/tag/13.15.22

-- 
*Karol Wrótniak *
Senior Android Developer

*/*
[image: Logo]

www.droidsonroids.com <https://www.thedroidsonroids.com/>
Wrocław, ul. Sikorskiego 26, 53-659 Poland

[image: Clutch Profile] <https://clutch.co/profile/droids-roids> [image:
Dribbble Profile] <https://dribbble.com/DroidsOnRoids> [image: Behance
Profile] <https://www.behance.net/droidsonroids> [image: Instagram Profile]
<https://www.instagram.com/droidsonroidsmobile/> [image: Github Profile]
<https://github.com/DroidsOnRoids> [image: X Profile]
<https://twitter.com/droidsonroids> [image: Facebook Profile]
<https://www.facebook.com/droidsonroids> [image: Linkedin Profile]
<https://pl.linkedin.com/company/droids-on-roids?trk=public_profile_topcard-current-company>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/

References

Raw JSON
{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "CVE-2025-12758 Unicode Variation",
          "vendor": "Cve",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Karol Wrótniak"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Summary\n=======\nA vulnerability was discovered in the popular JavaScript library\n'validator'.\nThe isLength() function incorrectly handles Unicode Variation Selectors\n(U+FE0E and U+FE0F). An attacker can inject thousands of these zero-width\ncharacters into a string, causing the library to report a much smaller\nperceived length than the actual byte size. This leads to validation\nbypasses,\npotential database truncation, and Denial of Service (DoS).\n\nMetadata\n========\nCVE ID: CVE-2025-12758\nVulnerability Type: Incomplete Filtering of Special Elements (CWE-792)\nAffected Package: validator (npm)\nAffected Versions: < 13.15.22\nFixed Version: 13.15.22\nCVSS Score: 7.5 (High) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H\n\nDescription\n===========\nThe 'validator' library's isLength() method is widely used to enforce\nconstraints on input data. However, the implementation failed to account\nfor\nUnicode Variation Selectors. These are zero-width code points that modify\nthe\npresentation of the preceding character (e.g., changing a text character\ninto\nan emoji).\n\nBecause these characters have zero width but occupy bytes in memory (UTF-16\nsurrogate pairs or single code points depending on the environment), an\nattacker can craft a payload that:\n1. Appears to have a length of 1 (e.g., 'a' followed by 5000 variation\nselectors).\n2. isLength() reports it as length 1 or 2 (depending on internal logic).\n3. The actual memory/storage size is massive (e.g., 10,000+ bytes).\n\nImpact\n======\n- Denial of Service (DoS): Sending extremely large payloads that pass\nlength\n  checks can exhaust server memory or CPU during processing.\n- Data Truncation: Databases with strict byte limits (e.g., VARCHAR(255))\n  may truncate the string, potentially leading to data corruption or\n  application logic errors.\n- Security Bypass: Bypassing UI or API limits intended to prevent large\n  blobs of data.\n\nProof of Concept (PoC)\n======================\nconst validator = require('validator');\n\n// 'a' followed by many Variation Selector-16 (\\uFE0F)\nconst payload = 'a' + '\\uFE0F'.repeat(5000);\n\nconsole.log(\"Actual length (chars):\", payload.length); // 5001\nconsole.log(\"Validator isLength(payload, {max: 5}):\",\n            validator.isLength(payload, {max: 5}));\n\n// In vulnerable versions, this returns 'true' because selectors\n// were not properly counted or were ignored in a way that bypassed\n// the total length check.\n\nFix\n===\nThe issue was fixed in version 13.15.22 by implementing a surgical fix\nthat correctly identifies and counts valid Unicode pairs and variation\nselectors, ensuring the reported length matches the actual data footprint\nmore accurately.\n\nTimeline\n========\n- 2025-10-18: Vulnerability reported to maintainers by Karol Wrótniak.\n- 2025-11-27: CVE-2025-12758 published.\n- 2025-11-09: Fixed version 13.15.22 released.\n\nReferences\n==========\n[1] https://www.thedroidsonroids.com/blog/when-zero-width-isnt-zero\n[2] https://nvd.nist.gov/vuln/detail/CVE-2025-12758\n[3] https://github.com/validatorjs/validator.js/releases/tag/13.15.22\n\n-- \n*Karol Wrótniak *\nSenior Android Developer\n\n*/*\n[image: Logo]\n\nwww.droidsonroids.com <https://www.thedroidsonroids.com/>\nWrocław, ul. Sikorskiego 26, 53-659 Poland\n\n[image: Clutch Profile] <https://clutch.co/profile/droids-roids> [image:\nDribbble Profile] <https://dribbble.com/DroidsOnRoids> [image: Behance\nProfile] <https://www.behance.net/droidsonroids> [image: Instagram Profile]\n<https://www.instagram.com/droidsonroidsmobile/> [image: Github Profile]\n<https://github.com/DroidsOnRoids> [image: X Profile]\n<https://twitter.com/droidsonroids> [image: Facebook Profile]\n<https://www.facebook.com/droidsonroids> [image: Linkedin Profile]\n<https://pl.linkedin.com/company/droids-on-roids?trk=public_profile_topcard-current-company>\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives & RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-792",
              "description": "CWE-792",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-09T10:07:08Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jan/27"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Jan/27"
        },
        {
          "url": "https://clutch.co/profile/droids-roids"
        },
        {
          "url": "https://dribbble.com/DroidsOnRoids"
        },
        {
          "url": "https://github.com/DroidsOnRoids"
        },
        {
          "url": "https://github.com/validatorjs/validator.js/releases/tag/13.15.22"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-12758"
        },
        {
          "url": "https://pl.linkedin.com/company/droids-on-roids?trk=public_profile_topcard-current-company"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://twitter.com/droidsonroids"
        },
        {
          "url": "https://www.behance.net/droidsonroids"
        },
        {
          "url": "https://www.facebook.com/droidsonroids"
        },
        {
          "url": "https://www.instagram.com/droidsonroidsmobile/"
        },
        {
          "url": "https://www.thedroidsonroids.com/"
        },
        {
          "url": "https://www.thedroidsonroids.com/blog/when-zero-width-isnt-zero"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Jan/27"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "CVE-2025-12758: Unicode Variation Selectors Bypass in 'validator' library (isLength)",
      "x_gcve": [
        {
          "recordType": "analysis",
          "relationships": [
            {
              "destId": "CVE-2025-12758",
              "type": "related"
            }
          ],
          "vulnId": "GCVE-1988-2026-0230",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jan/27",
            "automated": true,
            "contentSha256": "3f811160419685e23714b714c4bc76a905be3ad2cebf526de9f1b9e8a9f41764",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Jan/27",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-01-28T18:24:40Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-08T07:57:43Z",
    "dateUpdated": "2026-09-09T10:07:08Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0230"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}