validator
semver
>=13.15.20postconditions80functions50last verified2026-06-12coverage score100%Postconditions — what we check
- escape · escape-xss-preventionerrorWhenuser input rendered in HTML without escapingReturnsescaped string (always succeeds)Required handlingCaller MUST use escape() on ALL user input before rendering in HTML. Failure to escape allows XSS attacks, session hijacking, and data theft. CRITICAL: This is the #1 web security vulnerability.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- normalizeEmail · normalize-email-failureerrorWhenemail format is invalidReturnsfalse (boolean)Required handlingCaller MUST check return value. normalizeEmail() returns false for invalid emails, not a normalized string. Failing to check allows invalid emails to be stored, causing authentication failures.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2]
- normalizeEmail · normalize-email-spoofingwarningWhenemail not normalized before storageReturnsnormalized email string OR falseRequired handlingCaller MUST normalize emails before storage. Without normalization, users can create duplicate accounts via case differences (User@Example.com vs user@example.com) or Gmail +alias bypass (user+1@gmail.com).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3]
- isEmail · invalid-emailwarningWhenemail format is invalidReturnsfalse (boolean)Required handlingCaller MUST check return value. isEmail() returns false for invalid emails, it does NOT throw. Failing to check allows invalid emails into the system, causing authentication and delivery failures.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4]
- isEmail · email-not-validatedwarningWhenuser email not validated before storage or sendingReturnsfalse for invalid, true for validRequired handlingCaller MUST validate emails before storage or sending. Accepting invalid emails causes delivery failures, spam, and phishing attacks.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5]
- isURL · invalid-urlwarningWhenURL format is invalidReturnsfalse (boolean)Required handlingCaller MUST check return value. isURL() returns false for invalid URLs, it does NOT throw. Failing to check allows malformed URLs to pass through.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4]
- isURL · url-protocol-not-whitelistederrorWhenURL protocol not restricted to safe protocols (https only)Returnstrue for valid URL (including javascript:, data:, file: URIs)Required handlingCaller MUST whitelist URL protocols. Default isURL() accepts dangerous protocols like javascript:, data:, and file: which enable XSS and phishing. ALWAYS use: isURL(url, { protocols: ['https'], require_protocol: true })costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[6]
- isURL · url-validation-bypass-cveerrorWhenvalidator version < 13.15.20Returnstrue (but may incorrectly validate malicious URLs)Required handlingCRITICAL: CVE-2025-56200 affects validator < 13.15.20. The isURL() function has a validation bypass allowing XSS and open redirect attacks. Upgrade to 13.15.20+ immediately. Exploit POC available publicly.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[7]
- isJSON · invalid-jsonwarningWhenJSON format is invalidReturnsfalse (boolean)Required handlingCaller SHOULD use isJSON() before JSON.parse(). JSON.parse() throws SyntaxError on invalid JSON, crashing the application. isJSON() returns false safely, allowing graceful error handling.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5]
- isJSON · json-parse-without-validationwarningWhenJSON.parse() called on untrusted input without validationReturnsfalse for invalid JSONRequired handlingCaller SHOULD validate JSON before parsing. Without validation, malformed JSON from user input or external APIs causes uncaught SyntaxError exceptions, crashing the application or API endpoint.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[8]
- isStrongPassword · strong-password-weak-defaultswarningWhenisStrongPassword() called with default options for privileged accountsRequired handlingDefault options (minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1) may be insufficient for high-security applications. A password like "Password1!" satisfies all defaults but is trivially guessable. Callers accepting passwords for privileged accounts (admin, payment) SHOULD increase minLength to 12+ and consider minSymbols >= 2. NIST SP 800-63B recommends minimum 8 chars for regular accounts, 12+ for privileged accounts.costhighin prodsilent failureusers seesecurity breachvisibilitysilent
- isStrongPassword · strong-password-non-string-throwserrorWhenisStrongPassword() passed null, undefined, or non-stringThrows
TypeError: Expected a string but received a null/undefined/...Required handlingCaller MUST ensure the str argument is a string before calling isStrongPassword(). Common pattern: isStrongPassword(req.body.password) where the body field is missing (undefined) throws TypeError, crashing the request handler. Guard with: if (typeof password === 'string') { ... }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - isStrongPassword · strong-password-return-score-misreadwarningWhenisStrongPassword() called with returnScore: true, result used as booleanReturnsnumber (score) when returnScore: true — NOT a booleanRequired handlingWhen returnScore: true is passed, isStrongPassword() returns a NUMBER not a boolean. Any non-zero score evaluates as truthy, including scores for WEAK passwords. Callers MUST compare the score to an explicit threshold, not use it directly in an if() conditional. Use: const score = isStrongPassword(pwd, { returnScore: true }); if (score >= 40) { ... }costhighin prodsilent failureusers seesecurity breachvisibilitysilentSources[5]
- isJWT · jwt-format-only-not-verifiederrorWhenisJWT() used for authentication or authorization decisionsReturnstrue for any syntactically valid JWT (forged, expired, wrong issuer)Required handlingCRITICAL: isJWT() only validates that the string has JWT format (three base64url parts separated by dots). It does NOT verify the cryptographic signature, expiry (exp), issuer (iss), or audience (aud) claims. A forged JWT with valid structure passes isJWT() validation. Callers MUST use a proper JWT library (jsonwebtoken, jose) to verify the signature and claims. isJWT() is safe ONLY for format pre-screening before passing to a cryptographic verifier.costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- isJWT · jwt-non-string-throwserrorWhenisJWT() passed null, undefined, or non-string (e.g. missing Authorization header)Throws
TypeError: Expected a string but received a null/undefined/...Required handlingCaller MUST ensure the argument is a string before calling isJWT(). Common pattern: isJWT(req.headers.authorization) where the header is missing returns undefined, which throws TypeError. Guard with: if (typeof token === 'string' && isJWT(token)) { ... }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - stripLow · strip-low-not-xss-defensewarningWhenstripLow() output rendered in HTML without also calling escape()Returnsstring with control chars removed but HTML-active chars intactRequired handlingstripLow() removes control characters but does NOT sanitize HTML special characters (<, >, &, ", '). It is NOT a substitute for escape() for XSS prevention. Callers who use stripLow() in place of escape() for HTML rendering remain vulnerable to XSS. ALWAYS also call escape() on any output that will be rendered in HTML.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- stripLow · strip-low-newline-optionwarningWhenstripLow() used on multiline content without keep_new_lines: trueReturnsstring with newlines removed (default behavior)Required handlingBy default (keep_new_lines=false), stripLow() removes newline characters (0x0A, 0x0D). Callers processing multiline user content (addresses, notes, log entries) SHOULD use stripLow(str, true) to preserve newlines while still removing other control characters. Omitting this option silently strips line breaks, corrupting multiline content.costlowin prodsilent failureusers seelost datavisibilitysilentSources[3]
- toDate · to-date-null-uncheckederrorWhentoDate() result used without null checkReturnsnull for invalid date stringsRequired handlingCaller MUST check for null before using the returned Date. toDate() returns null when the input string is not a valid date. Accessing any property on null (e.g., toDate(str).toISOString()) throws TypeError: Cannot read properties of null, crashing the handler for any invalid user-supplied date string. Guard with: const date = toDate(str); if (!date) { handle error }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3]
- toDate · to-date-timezone-ambiguitywarningWhentoDate() used with date strings lacking explicit timezoneReturnsDate with ambiguous timezone — UTC or local depending on formatRequired handlingtoDate() calls Date.parse() internally. Date.parse() behavior for dates without explicit timezone is implementation-defined (UTC for ISO 8601, local time for other formats). Result may differ between Node.js versions. Callers SHOULD use explicit ISO 8601 strings with timezone offset (e.g., "2024-01-15T10:30:00Z") for deterministic results.costlowin prodsilent failureusers seelost datavisibilitysilentSources[12]
- toFloat · to-float-nan-uncheckederrorWhentoFloat() result used in arithmetic without isNaN() checkReturnsNaN for invalid float stringsRequired handlingCaller MUST check isNaN() before using the result in arithmetic. toFloat() returns NaN for invalid float strings. Any arithmetic with NaN produces NaN (NaN propagation). Price calculations, currency conversions, and metric computations silently produce incorrect NaN results. Guard with: const val = toFloat(str); if (isNaN(val)) { throw new Error(...) }costhighin prodsilent failureusers seelost transactionvisibilitysilentSources[3]
- toInt · to-int-nan-uncheckederrorWhentoInt() result used without isNaN() checkReturnsNaN for invalid or non-numeric integer stringsRequired handlingCaller MUST check isNaN() before using the result. toInt() returns NaN for invalid integer strings. Common pattern: toInt(req.query.page) returns NaN for missing/invalid page parameter, then NaN used as SQL LIMIT/OFFSET crashes the query or returns incorrect results. Guard with: const page = toInt(str); if (isNaN(page)) { handle error }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3]
- toInt · to-int-radix-defaultwarningWhentoInt() used with hex-prefixed strings (0x...) without explicit radixReturns0 for '0x...' strings when radix defaults to 10Required handlingtoInt() defaults to radix 10. If the input string has a leading "0x" prefix (e.g., "0x1F"), parseInt() with radix 10 returns 0 (parses only the leading digit before "x"). Callers processing hex strings MUST pass radix 16 explicitly: toInt(str, 16). Callers processing untrusted input should NOT use toInt() for hex values without explicit radix.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[13]
- isCreditCard · credit-card-format-onlyerrorWhenisCreditCard() used as substitute for payment processor authorizationReturnstrue for Luhn-valid card numbers including test cards (4111111111111111)Required handlingCRITICAL: isCreditCard() validates format and Luhn checksum only — it does NOT verify that the card exists, has funds, is not stolen, or is not expired. A test card number like "4111111111111111" (Visa test) passes isCreditCard(). Callers MUST NOT use isCreditCard() as a substitute for payment processor authorization. ALWAYS submit cards to a payment processor (Stripe, Braintree) for actual authorization. isCreditCard() is only for UX format feedback.costhighin prodsilent failureusers seelost transactionvisibilitysilent
- isCreditCard · credit-card-non-string-throwserrorWhenisCreditCard() passed null, undefined, or non-stringThrows
TypeError: Expected a string but received a null/undefined/...Required handlingCaller MUST ensure the argument is a string before calling isCreditCard(). Pattern: isCreditCard(req.body.cardNumber) where the field is missing (undefined) throws TypeError, crashing the payment form handler with HTTP 500. Guard with: if (typeof cardNumber === 'string') { ... }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - matches · matches-redos-user-patternerrorWhenmatches() called with a user-supplied pattern or modifiersReturnsboolean — but string pattern compiled without ReDoS protectionRequired handlingCRITICAL: The validator README explicitly states matches() patterns are NOT checked for ReDoS attacks and user-provided patterns are NOT recommended. When the pattern argument is a string (not a RegExp literal), it is compiled via new RegExp(pattern, modifiers) at runtime. A malicious user can supply a catastrophic backtracking pattern like "(a+)+" that causes exponential backtracking, halting the Node.js event loop. Callers MUST: (1) never pass user-supplied strings directly as the pattern, (2) only use hardcoded RegExp literals as the pattern argument, or (3) use a ReDoS-safe regex library (e.g., safe-regex, re2) for user-supplied patterns.costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- matches · matches-non-string-throwserrorWhenmatches() passed null, undefined, or non-string as the first argumentThrows
TypeError: Expected a string but received a null/undefined/...Required handlingCaller MUST ensure the str argument is a string before calling matches(). Pattern: matches(req.body.field, /regex/) where the body field is missing (undefined) throws TypeError, crashing the request handler. Guard with: if (typeof field === 'string' && matches(field, /pattern/)) { ... }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - isCurrency · currency-locale-mismatchwarningWhenisCurrency() used to validate non-US currency without locale optionsReturnsfalse for valid non-US currency strings (e.g. EUR '1.234,56' fails)Required handlingisCurrency() defaults to US format: symbol '$', thousands_separator ',', decimal_separator '.'. European-format amounts like "1.234,56" (German EUR) or "£1,234.56" (GBP) fail validation with default options because the thousands and decimal separators are reversed. Multi-currency applications MUST configure: isCurrency(amount, { symbol: '€', thousands_separator: '.', decimal_separator: ',' }) for EU formats. Silently rejecting valid foreign currency amounts causes payment form rejection and lost transactions.costmediumin prodsilent failureusers seelost transactionvisibilitysilentSources[5]
- isCurrency · currency-symbol-not-requiredwarningWhenisCurrency() used for financial input where symbol presence is requiredReturnstrue for bare numbers like '1234.56' (symbol optional by default)Required handlingBy default, require_symbol is false — isCurrency() accepts bare numeric strings like "1234.56" without a currency symbol. If your application requires a symbol to distinguish currency from plain numbers, use: isCurrency(amount, { require_symbol: true }). Without this, user input lacking a currency symbol passes validation, potentially causing incorrect storage or display of amounts in multi-currency contexts.costlowin prodsilent failureusers seelost datavisibilitysilentSources[5]
- isBase64 · base64-urlsafe-confusionwarningWhenisBase64() used to validate JWT payloads, URL tokens, or OAuth state without urlSafe: trueReturnsfalse for valid base64url strings (- and _ chars fail standard base64 check)Required handlingStandard base64 uses + and / characters. URL-safe base64 (base64url) uses - and _ instead. JWT headers and payloads use base64url encoding. Default isBase64() with { urlSafe: false } will return false for valid JWT segments because they contain - and _ characters. Always use: isBase64(str, { urlSafe: true }) when validating JWT parts, OAuth state tokens, or any URL-embedded base64. Using wrong encoding causes false rejections of valid tokens, breaking authentication flows.costmediumin prodsilent failureusers seeservice unavailablevisibilityvisible
- isBase64 · base64-empty-string-validwarningWhenisBase64('') used as truthy guard for non-empty inputReturnstrue for empty string ''Required handlingisBase64() returns true for empty string '' — an empty string is considered a valid (zero-byte) base64 value. Callers using isBase64() as a guard before decoding must also check for non-empty input: if (str && isBase64(str)) { ... } Otherwise, empty string passes the base64 check and atob('') or Buffer.from('', 'base64') succeeds silently, resulting in empty output that may not be detected.costlowin prodsilent failureusers seelost datavisibilitysilentSources[17]
- isLength · length-vs-string-length-mismatchwarningWhenisLength() result compared with str.length for same stringReturnstrue for strings where isLength(str, {max: N}) === true but str.length > NRequired handlingisLength() counts grapheme clusters — surrogate pairs (emoji like 😀, some CJK characters) count as 1 character in isLength() but 2 in str.length. A string like "Hello😀" passes isLength(str, {max: 6}) but str.length returns 7. Callers that enforce database column limits MUST use isLength() (not str.length) to avoid truncation on storage. Conversely, callers computing byte sizes for binary protocols must use Buffer.byteLength() — isLength() counts visible chars, not bytes. Mixing these causes either data truncation or incorrect validation.costmediumin prodsilent failureusers seelost datavisibilitysilent
- isISO8601 · iso8601-non-strict-invalid-dateserrorWhenisISO8601() used without strict: true to validate calendar dates for storageReturnstrue for structurally valid but calendar-invalid dates (e.g. '2009-02-29')Required handlingWithout { strict: true }, isISO8601() validates the string format only — not calendar validity. "2009-02-29" (February 29 in a non-leap year) returns true because the format is correct even though the date does not exist. When this invalid date is then parsed (Date.parse, new Date()), the result may be rolled over to March 1, silently storing incorrect dates. For any application storing calendar dates (appointments, birthdays, deadlines), ALWAYS use: isISO8601(dateStr, { strict: true })costmediumin prodsilent failureusers seelost datavisibilitysilentSources[5]
- isISO8601 · iso8601-strict-separatorwarningWhenisISO8601() used for API interoperability without strictSeparator: trueReturnstrue for '2024-01-15 10:30:00' (space separator) when only T separator requiredRequired handlingWithout { strictSeparator: true }, isISO8601() accepts both 'T' and space as the date-time separator. RFC 3339 and most REST APIs require the 'T' separator. "2024-01-15 10:30:00Z" passes isISO8601() but may be rejected by strict API parsers (PostgreSQL TIMESTAMPTZ, Go's time.Parse with RFC3339 layout, Java's Instant.parse). For API-to-API data exchange, use: isISO8601(str, { strict: true, strictSeparator: true })costlowin prodsilent failureusers seelost datavisibilitysilent
- isLicensePlate · license-plate-invalid-locale-throwserrorWhenisLicensePlate() called with a locale string not in the supported set ('cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'en-SG', 'en-PK', 'es-AR', 'fi-FI', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE') and not 'any'. This happens when: (1) a locale derived from user input or environment variable is passed directly without validation, (2) a newly-added locale from the frontend doesn't match validator.js supported set, (3) using 'en-US' (not supported — no US state-level logic in validator.js).Throws
Error with message "Invalid locale '<locale>'". Note: This is a plain Error, not TypeError. Unlike the ubiquitous assertString() TypeError (which fires on non-string input), this error fires on VALID string input with an unrecognized locale name. Callers that catch TypeError only will NOT catch this error.Required handlingAlways validate the locale before calling isLicensePlate(): const SUPPORTED_LOCALES = new Set([ 'cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'en-SG', 'en-PK', 'es-AR', 'fi-FI', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE', 'any' ]); if (!SUPPORTED_LOCALES.has(locale)) { // fall back to 'any' or return false locale = 'any'; } const isValid = isLicensePlate(plateStr, locale); For international apps that add new locales: upgrade validator.js version or use 'any' locale as fallback to avoid hard crashes on unrecognized country codes.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isLicensePlate · license-plate-any-locale-perfwarningWhenisLicensePlate(str, 'any') used in hot paths (request handlers, batch validation loops) without awareness that 'any' iterates through ALL supported locales sequentially. When str doesn't match any locale, isLicensePlate() tries each of the 13 locale validators in turn — each with complex regex — before returning false.Returnstrue if any locale's regex matches; false after exhausting all 13 validatorsRequired handlingWhen validation performance matters, pass the specific locale if known: isLicensePlate(plateStr, 'en-IN') // O(1) — single regex check instead of: isLicensePlate(plateStr, 'any') // O(n) — iterates all 13 locales For user-submitted forms where the locale is unknown, consider adding a dropdown or country selector to collect the locale rather than using 'any'.costlowin proddegraded serviceusers seedegraded performancevisibilitysilentSources[20]
- isBase32 · base32-crockford-confusionwarningWhenCrockford Base32-encoded data (used by ULID, NanoID, some blockchain identifiers) validated without { crockford: true } option. Crockford Base32 excludes ambiguous characters (I, L, O, U) and uses digits 0-9 alongside letters. Standard Base32 uses only A-Z and 2-7. A valid Crockford Base32 string WILL fail isBase32() with default options because: (1) Crockford allows digits 0, 1, 3-9 which aren't in [A-Z2-7] (2) Crockford strings have no padding (= chars) (3) Crockford strings may not be length % 8Returnsfalse for valid Crockford Base32 strings when crockford option is not setRequired handlingDetermine which encoding standard your data uses before calling isBase32(): // Standard RFC 4648 Base32 (e.g., TOTP secrets, many crypto keys): isBase32(str) // or { crockford: false } // Example valid: 'MFRA====', length must be multiple of 8 // Crockford Base32 (used by ULID, NanoID, Hashids): isBase32(str, { crockford: true }) // Example valid: '01ARYZ6S41', no padding required The two are not interchangeable. A ULID (always Crockford Base32) will always fail standard isBase32() — returning false, not throwing, causing silent validation failures that reject valid data.costlowin prodsilent failureusers seelost datavisibilitysilent
- isMobilePhone · mobile-phone-invalid-locale-throwserrorWhenisMobilePhone() called with a locale string not in the supported set and not 'any'. Common causes: (1) locale derived from user input or Accept-Language header passed directly without normalization, (2) using 'en-US' when the library expects 'en-US' but with a subtle variation, (3) using a locale like 'en' (must be 'en-US', 'en-GB', etc.), (4) configuration file lists an unsupported locale added for a new market.Throws
Error with message "Invalid locale '<locale>'". This is a plain Error, not TypeError. Callers that catch TypeError only will NOT catch this. Unlike assertString's TypeError (which fires on non-string first argument), this error fires on valid string input with bad locale name.Required handlingValidate the locale before passing to isMobilePhone(): // Safe: use 'any' when locale is unknown or user-provided isMobilePhone(phone, 'any') // tries all 200+ locale patterns // Better: validate locale against supported set first const SUPPORTED_LOCALES = new Set(require('validator').isMobilePhone.locales); const safeLocale = SUPPORTED_LOCALES.has(locale) ? locale : 'any'; isMobilePhone(phone, safeLocale) For international apps: never pass Accept-Language header values directly as the locale parameter without normalization.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isPostalCode · postal-code-invalid-locale-throwserrorWhenisPostalCode() called with a locale string not in the supported set and not 'any'. Common causes: (1) using ISO 3166-1 alpha-3 ('USA') instead of alpha-2 ('US'), (2) using a locale code not yet in validator.js (e.g., newly supported country), (3) deriving locale from user-submitted country form field without validation, (4) using lowercase ('us') when the library expects uppercase ('US').Throws
Error with message "Invalid locale '<locale>'". Plain Error, not TypeError. Callers catching only TypeError will miss this. The locale string itself is valid — it is just unrecognized by validator.js.Required handlingAlways use 'any' when locale is user-provided or not guaranteed to be in the supported set, or pre-validate against the supported list: // Safe fallback: 'any' accepts any valid postal code format from ~32 countries isPostalCode(code, 'any') // Explicit locale: valid for 'AD', 'AT', 'AU', 'BE', 'BG', 'CA', 'CH', // 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', // 'HU', 'ID', 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', // 'LU', 'LV', 'MT', 'MX', 'MY', 'NL', 'NO', 'NZ', 'PL', 'PR', 'PT', // 'RO', 'RU', 'SA', 'SE', 'SI', 'SK', 'TH', 'TN', 'TW', 'UA', 'US', // 'ZA', 'ZM' isPostalCode(code, 'US')costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isTaxID · tax-id-invalid-locale-throwserrorWhenisTaxID() called with a locale string not in the supported set. Common causes: (1) using 'en-AU' (Australia not supported — returns false, no throw... unless locale is completely unrecognized), (2) passing a country ISO code ('US') instead of full locale ('en-US'), (3) deriving locale from i18n configuration that uses different locale naming conventions, (4) using 'en' or 'de' instead of 'en-US' or 'de-DE'.Throws
Error with message "Invalid locale '<locale>'". Plain Error (not TypeError). Thrown when locale string is not found in the taxIdFormat object. Callers that use typeof checks or catch TypeError only will not catch this runtime exception.Required handlingAlways validate locale before calling isTaxID(), or use a try-catch: try { const isValid = isTaxID(str, locale); } catch (e) { if (e.message.startsWith('Invalid locale')) { // locale not supported, handle gracefully return false; } throw e; } For financial applications: verify the exact locale strings supported by your installed validator.js version before adding a new country market.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isVAT · vat-invalid-country-code-throwserrorWhenisVAT() called with a country code not in the supported EU/UK set. Common causes: (1) using an EU candidate country code not yet in validator.js, (2) passing a 3-letter code ('GBR') instead of 2-letter ('GB'), (3) using lowercase ('gb') when uppercase ('GB') is required, (4) using 'EU' as a generic EU VAT prefix instead of the member country code.Throws
Error with message "Invalid country code: '<countryCode>'". Note: error message format differs from other locale-throwing functions (uses "Invalid country code:" not "Invalid locale"). Callers must handle this specific message format when catching expected locale/country errors.Required handlingValidate the country code before calling isVAT(), or wrap in try-catch: const SUPPORTED_VAT_COUNTRIES = new Set([ 'AL', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'EL', 'ES', 'EU', 'FI', 'FR', 'GB', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK' ]); if (!SUPPORTED_VAT_COUNTRIES.has(countryCode.toUpperCase())) { return false; // unsupported country, skip VAT check } return isVAT(vatNumber, countryCode.toUpperCase());costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isIdentityCard · identity-card-invalid-locale-throwserrorWhenisIdentityCard() called with a locale string not in the supported set and not 'any'. Common causes in KYC/identity verification systems: (1) using a country code ('CN') instead of locale ('zh-CN'), (2) adding support for a new country whose locale is not yet in validator.js, (3) user-submitted country dropdown value passed directly as locale parameter.Throws
Error with message "Invalid locale '<locale>'". Plain Error (not TypeError). Identity verification flows that catch only TypeError or only check for falsy return values will surface this as an unhandled exception in production.Required handlingUse 'any' when the identity card type is unknown or user-provided, or pre-validate the locale: // Safe: 'any' tries all supported patterns isIdentityCard(idNumber, 'any') // Validated explicit locale const SUPPORTED = ['ar-LY', 'ar-TN', 'es-EC', 'fr-TN', 'he-IL', 'hr-HR', 'hu-HU', 'id-ID', 'it-IT', 'LK', 'MS', 'nl-NL', 'sk-SK', 'sr-RS', 'zh-CN', 'zh-HK', 'zh-TW']; const locale = SUPPORTED.includes(userLocale) ? userLocale : 'any'; isIdentityCard(idNumber, locale)costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - unescape · unescape-xss-reintroductionerrorWhenunescape() output rendered directly in HTML without re-escaping. Occurs when: (1) data is stored escaped in database, retrieved, unescaped, then rendered in a template — the unescape call negates the original protection, (2) an "unescape for display" step is added to a data pipeline that also renders to HTML, (3) using unescape() to "clean up" data before passing to another validator that doesn't need HTML-encoded input.ReturnsString with all HTML entities converted back to literal characters. The returned string contains raw <, >, &, ", ', / characters that are DANGEROUS in HTML rendering contexts.Required handlingNever render unescape() output directly in HTML without calling escape() again. The canonical safe pattern is to store raw strings (not HTML-encoded) and escape only at render time: // WRONG: store encoded, unescape for comparison, render without re-escaping const stored = validator.escape(userInput); // stored in DB const raw = validator.unescape(stored); // retrieved later template.innerHTML = raw; // ← XSS vulnerability! // RIGHT: store raw, escape only when rendering HTML const stored = userInput; // store raw template.innerHTML = validator.escape(stored); // escape at render time Use unescape() only when the unescaped output will NOT be rendered in HTML (e.g., logging, plaintext email body, API response body in JSON).costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- blacklist · blacklist-regex-injectionwarningWhenblacklist() called where the `chars` argument derives from user input, a configuration value, or a database field that may contain regex metacharacters (], [, ^, -, \, ., *, +, ?, (, ), {, }, |). For example: blacklist(input, userSuppliedCharsToRemove) where the chars value contains '-' would be interpreted as a range operator in the character class, potentially making the regex match unintended characters or throw a SyntaxError.Throws
SyntaxError when chars contains invalid regex syntax (e.g., unbalanced brackets, invalid character class ranges like 'z-a'). May silently match unintended characters when chars contains range operators like '-' or '^'.Required handlingNever pass user-controlled values as the `chars` argument. If chars must be dynamic, escape regex special characters before passing: function safeBlacklist(str, chars) { // Escape special regex chars in the character class const escapedChars = chars.replace(/[-[\]^\\]/g, '\\$&'); return validator.blacklist(str, escapedChars); } For static char lists (hardcoded strings), verify the string contains no regex metacharacters. Use whitelist() (or trim/replace) when you know exactly which characters to KEEP rather than remove.costmediumin prodsilent failureusers seelost datavisibilitysilent - whitelist · whitelist-regex-injectionwarningWhenwhitelist() called where the `chars` argument derives from user input, a config file, or a variable that may contain regex metacharacters. Same attack surface as blacklist(): '-', '^', ']', '\' in chars cause unintended regex behavior. Additionally, '^' at the start of chars inverts the logic (already negated in the pattern), potentially passing all characters through.Throws
SyntaxError when chars produces invalid regex syntax. May silently pass through characters that should have been removed when chars contains range or negation metacharacters.Required handlingAlways use hardcoded chars strings. For dynamic whitelist characters, escape before passing: // Wrong: dynamic chars from config whitelist(input, allowedCharsFromConfig) // Right: hardcoded explicit character set whitelist(input, 'a-zA-Z0-9') // letters and digits only whitelist(input, '0-9') // digits only // If dynamic is unavoidable: const escaped = chars.replace(/[-[\]^\\]/g, '\\$&'); whitelist(input, escaped)costmediumin prodsilent failureusers seelost datavisibilitysilent - toBoolean · to-boolean-loose-mode-truthy-surprisewarningWhentoBoolean() called without strict=true in a security-sensitive context where the string value comes from user input, environment variables, or query parameters. In non-strict mode, 'no', 'off', 'disabled', 'false' (wrong case would still be 'false'), 'null', '0.0', 'FALSE' — all return true because only the exact strings '0', 'false', and '' return false. Examples: toBoolean('no') → true, toBoolean('off') → true, toBoolean('null') → true, toBoolean('0.0') → true.Returnstrue for any string that is not exactly '0', 'false' (case-sensitive), or '' in non-strict mode. This is counterintuitive — many strings that humans read as "falsy" (like 'no', 'off', 'disabled') return true.Required handlingUse strict mode (toBoolean(str, true)) when parsing boolean config values, feature flags, or any string that may be 'yes'/'no', 'on'/'off', or natural language booleans: // Non-strict (default) — only use when you trust the source to be '0'/'false'/'' toBoolean('no') // → true (SURPRISE: 'no' is truthy!) toBoolean('off') // → true (SURPRISE: 'off' is truthy!) toBoolean('0.0') // → true (SURPRISE: '0.0' is truthy!) // Strict mode — only '1' and 'true' return true toBoolean('yes', true) // → false (as expected) toBoolean('1', true) // → true (as expected) toBoolean('true', true) // → true (as expected) toBoolean('on', true) // → false For environment variables and feature flags, always use strict mode: const isFeatureEnabled = toBoolean(process.env.FEATURE_FLAG, true);costmediumin prodsilent failureusers seelost datavisibilitysilent
- trim · trim-non-string-throwswarningWhentrim(), ltrim(), or rtrim() called with a non-string first argument. Common in form processing pipelines where fields may be null (optional fields not submitted), undefined (object property not set), or numbers (age, price parsed from JSON before being passed to trim for "just in case" sanitization). Contrast with JavaScript's native String.prototype.trim() which doesn't exist on null/undefined.Throws
TypeError with message "Expected a string but received a <type>". Thrown by assertString() before any trimming occurs. Non-string values like null, undefined, 0, or objects cause immediate TypeError.Required handlingAlways ensure the input is a string before calling trim(): // Wrong: may receive null from optional form field const cleanName = validator.trim(req.body.name); // Right: coerce or guard first const cleanName = validator.trim(String(req.body.name ?? '')); // Or use optional chaining with fallback const cleanName = req.body.name ? validator.trim(req.body.name) : '';costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isByteLength · isbytelength-byte-vs-char-confusionwarningWhenisByteLength() used to validate string length against a limit derived from a database column size or API constraint, where the column stores multibyte characters (CJK, Arabic, emoji, accented Latin). The max option reflects the column's byte capacity, not its character capacity. Example: VARCHAR(100) means 100 bytes in some databases (MySQL latin1), or 100 chars in others (MySQL utf8mb4 stores 1-4 bytes per char). Code that passes isByteLength({max: 100}) for a utf8mb4 VARCHAR(100) column will REJECT valid CJK strings that fit the column because it conflates bytes and chars. Conversely, code that uses isLength({max: 100}) for a VARCHAR(100) byte-limited column will ALLOW overlong multibyte strings that EXCEED the DB column's capacity.Returnsfalse when the byte length exceeds max — but this can falsely reject valid input if the limit was meant as a character limit, or falsely accept overlong input if isLength() was used instead for a byte-limited column.Required handlingUse isByteLength() only when the constraint is a BYTE limit (e.g. Redis key/value byte caps, fixed-width binary fields, HTTP header length limits). Use isLength() when the constraint is a CHARACTER limit (e.g. display name max characters, tweet length, most UI character counters). For database columns: check whether the column type stores length in bytes or characters. MySQL utf8mb4 CHAR(n) = n characters; VARCHAR(n) = n bytes. PostgreSQL TEXT/VARCHAR(n) = n characters. // Wrong: Assumes column limit is characters, not bytes if (!validator.isByteLength(name, { max: 100 })) reject('name too long'); // May reject valid CJK name 'が大切' (3 chars = 9 bytes) // Right for byte-limited storage: if (!validator.isByteLength(value, { max: 256 })) reject('value too large'); // Right for character-limited display (most UI use cases): if (!validator.isLength(name, { max: 100 })) reject('name too long');costlowin prodsilent failureusers seelost datavisibilitysilent
- isByteLength · isbytelength-non-string-throwswarningWhenisByteLength() called with a non-string first argument. Common when processing JSON payload fields that may be null (optional fields), numbers, or objects before string validation.Throws
TypeError with message "Expected a string but received a <type>". Thrown by assertString() before the byte count is computed.Required handlingGuard or coerce to string before calling: // Wrong: may receive null from optional JSON field const valid = validator.isByteLength(req.body.description, { max: 255 }); // Right: guard first const desc = req.body.description; if (typeof desc !== 'string') return reject('description required'); const valid = validator.isByteLength(desc, { max: 255 });costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - isWhitelisted · iswhitelisted-null-chars-throwswarningWhenisWhitelisted() called where the `chars` parameter is null, undefined, or a value that does not have an indexOf() method. This differs from all other is* validators whose only TypeError comes from a null/non-string FIRST argument. Here the SECOND argument (chars) can also throw. Occurs when chars is loaded from a config file or environment variable that may be absent, or when it's derived from user input without validation.Throws
TypeError: "Cannot read properties of null (reading 'indexOf')" when chars is null. TypeError: "Cannot read properties of undefined (reading 'indexOf')" when chars is undefined. This is NOT an assertString() error — it originates from the chars.indexOf() call inside the loop after assertString(str) has already succeeded.Required handlingAlways ensure chars is a non-null string before calling isWhitelisted(): // Wrong: chars from config may be undefined const allowed = config.allowedChars; // may be undefined if (!validator.isWhitelisted(input, allowed)) throw new Error('invalid chars'); // => TypeError: Cannot read properties of undefined (reading 'indexOf') // Right: validate or default chars const allowed = config.allowedChars ?? 'abcdefghijklmnopqrstuvwxyz0123456789'; if (!validator.isWhitelisted(input, allowed)) throw new Error('invalid chars');costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isWhitelisted · iswhitelisted-unchecked-returnwarningWhenisWhitelisted() return value not checked, or checked but the application proceeds with the unvalidated input when it returns false. Unlike blacklist() which REMOVES disallowed chars from the string, isWhitelisted() only REPORTS whether disallowed chars are present — it does not sanitize. Callers who mistake it for a sanitizer instead of a validator pass through invalid input.Returnsfalse when any character in str is not in chars. The string is NOT modified. Returning false means the input is INVALID — the caller must reject it.Required handlingAlways act on the boolean return value. Do not pass the original string through after isWhitelisted returns — the string is unchanged: // Wrong: confuses validator with sanitizer const safe = validator.isWhitelisted(userInput, 'a-z0-9'); // safe is boolean, NOT a sanitized string — but name implies it "whitelisted" the value db.query('INSERT INTO tags VALUES (' + userInput + ')'); // userInput unchanged! // Right: check and reject if (!validator.isWhitelisted(userInput, 'abcdefghijklmnopqrstuvwxyz0123456789-')) { return res.status(400).json({ error: 'Invalid characters in tag name' }); } db.query('INSERT INTO tags VALUES (?)', [userInput]);costlowin prodsilent failureusers seelost datavisibilitysilentSources[5]
- isAlpha · alpha-invalid-locale-throwserrorWhenisAlpha() called with a locale string not in the supported 76-locale set. Common in internationalized form validation: (1) locale derived from req.acceptsLanguages() or user profile settings passed directly without normalization, (2) using 'zh-CN' when 'zh-CN-Simplified' is the actual key (zh-CN IS supported in isAlpha, but similar subtleties exist), (3) using POSIX locale formats ('en_US') instead of BCP 47 ('en-US'), (4) adding a new market's locale that isAlpha doesn't yet support.Throws
Error with message "Invalid locale '<locale>'". Plain Error (not TypeError). This fires on valid string input with unrecognized locale name — different from assertString()'s TypeError which fires on null/non-string input. Callers that catch TypeError will NOT catch this locale error.Required handlingValidate the locale before calling isAlpha(), or use a try-catch: // Safe: pre-validate using the built-in locales list const { isAlpha } = require('validator'); const supportedLocales = new Set(isAlpha.locales); const safeLocale = supportedLocales.has(userLocale) ? userLocale : 'en-US'; isAlpha(name, safeLocale) // Or wrap in try-catch for dynamic locale values try { const isValid = isAlpha(name, locale); } catch (e) { if (e.message.startsWith('Invalid locale')) { return false; // unsupported locale, skip alpha check } throw e; } Never pass Accept-Language header values or user-submitted locale strings directly as the locale parameter without normalization.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isAlpha · alpha-ignore-type-throwswarningWhenisAlpha() called with the ignore option set to a non-string, non-RegExp value. The ignore option allows certain characters to be excluded from alpha checking (e.g., ignore spaces in 'hello world'). When passed a number, array, or object instead of a string or RegExp, isAlpha throws. Common when ignore is built dynamically from config or user input.Throws
Error with message "ignore should be instance of a String or RegExp". Plain Error (not TypeError). Occurs when options.ignore is set but is not a string or RegExp instance (e.g., ignore: [' ', '-'] passes an array).Required handlingAlways ensure the ignore option is a string or RegExp before calling isAlpha(): // Wrong: passing array for multiple chars to ignore isAlpha('hello world', 'en-US', { ignore: [' ', '-'] }) // throws! // Right: pass a string of chars to ignore isAlpha('hello world', 'en-US', { ignore: ' -' }) // ' ' and '-' ignored // Right: pass a RegExp isAlpha('hello world', 'en-US', { ignore: /[\s-]/g })costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[37] - isAlphanumeric · alphanumeric-invalid-locale-throwserrorWhenisAlphanumeric() called with a locale string not in the supported 76-locale set. More commonly encountered than isAlpha locale errors because username/username validation is often locale-aware in globalized apps. A locale added to the frontend for display purposes may not match the validator.js locale set, causing the username validation handler to throw instead of returning false.Throws
Error with message "Invalid locale '<locale>'". Plain Error (not TypeError). Callers catching only TypeError miss this. Fires on valid string input with unrecognized locale — not on null/undefined input.Required handlingPre-validate locale or use try-catch: const { isAlphanumeric } = require('validator'); const supportedLocales = new Set(isAlphanumeric.locales); const safeLocale = supportedLocales.has(locale) ? locale : 'en-US'; const isValid = isAlphanumeric(username, safeLocale);costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isAlphanumeric · alphanumeric-ignore-type-throwswarningWhenisAlphanumeric() called with ignore option set to a non-string, non-RegExp value. Same pattern as isAlpha's ignore option. Thrown when ignore is an array, number, object, or other non-string type.Throws
Error with message "ignore should be instance of a String or RegExp". Plain Error (not TypeError). Thrown before the locale check runs.Required handlingPass ignore as a string of characters to exclude or as a RegExp: // Wrong isAlphanumeric('user-name', 'en-US', { ignore: ['-'] }) // throws! // Right isAlphanumeric('user-name', 'en-US', { ignore: '-' }) isAlphanumeric('user.name', 'en-US', { ignore: /[.-]/g })costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[38] - isDecimal · decimal-invalid-locale-throwserrorWhenisDecimal() called with a locale option not in the 68-locale supported set. The locale option controls which decimal separator character is expected (e.g. 'de-DE' accepts '1,5' as valid decimal). Passing an unsupported locale string throws instead of returning false, crashing the validation handler for financial input.Throws
Error with message "Invalid locale '<locale>'". Plain Error (not TypeError). Thrown when options.locale is not in the supported decimal locale set. Note: the locale key in options, not a positional argument.Required handlingValidate locale or use try-catch. The decimal locales are accessible as: const alpha = require('validator/lib/alpha'); const supportedDecimalLocales = Object.keys(alpha.decimal); // Includes: en-US, de-DE, fr-FR, ar, es-ES, etc. (68 total) // Safe pattern const safeLocale = supportedDecimalLocales.includes(locale) ? locale : 'en-US'; isDecimal(priceStr, { locale: safeLocale })costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isDecimal · decimal-force-decimal-not-setwarningWhenisDecimal() used to validate price or financial input where integers (without a decimal point) should be rejected. By default force_decimal is false, meaning isDecimal('100') returns true — an integer passes the decimal validator. Financial forms that require prices like '100.00' (not just '100') will silently accept integers if force_decimal is not set.Returnstrue for integers like '100', '0', '-5' when force_decimal is false (default). Returns false for those same strings when force_decimal: true.Required handlingWhen validating monetary amounts that require an explicit decimal component, use force_decimal: true: // Wrong: accepts integers as valid prices isDecimal(price) // '100' → true, '100.00' → true // Right for strict decimal requirement isDecimal(price, { force_decimal: true }) // '100' → false, '100.00' → true For currency display-only validation (showing prices to users), consider isCurrency() which has more financial-specific options.costmediumin prodsilent failureusers seelost datavisibilitysilent
- isDate · isdate-non-strict-accepts-date-objectswarningWhenisDate() used in an API handler where the input may be either a string (from JSON body parsing) or a Date object. In non-strict mode, isDate(new Date()) returns true even though Date is not a string. This means a pre-parsed Date object silently passes string validation, bypassing subsequent string-specific sanitization steps. Also occurs when TypeScript's type system is bypassed (e.g., any type, JSON.parse output used without type assertion).Returnstrue for actual Date objects when strictMode is false (default). This means isDate() does NOT guarantee the input is a string — it may still be a Date object. All downstream string operations on the value (trim, split, slice) will then fail or produce unexpected results.Required handlingUse strictMode: true when you expect only strings: // Wrong: accepts both strings and Date objects if (!isDate(userInput)) return res.status(400).json({ error: 'Invalid date' }); const trimmed = userInput.trim(); // TypeError if userInput was a Date object! // Right: strict mode rejects Date objects, only accepts formatted strings if (!isDate(userInput, { strictMode: true, format: 'YYYY-MM-DD' })) { return res.status(400).json({ error: 'Invalid date, expected YYYY-MM-DD' }); }costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
- isDate · isdate-strict-format-mismatchwarningWhenisDate() called with strictMode: true but without explicitly specifying format, while the expected input format is 'YYYY-MM-DD' (ISO date). The default format option is 'YYYY/MM/DD' (slash separator, not dash). In strict mode, 'YYYY-MM-DD' strings like '2024-01-15' return FALSE unless format: 'YYYY-MM-DD' is set. The mismatch is subtle — the same string returns true in non-strict mode but false in strict mode with default format.Returnsfalse for '2024-01-15' in strict mode with default format ('YYYY/MM/DD'). Returns true for '2024/01/15' in strict mode with default format. This silently rejects valid ISO dates when callers use strict mode naively.Required handlingAlways specify the format explicitly when using strict mode: // Wrong: strict mode with default format rejects 'YYYY-MM-DD' strings isDate('2024-01-15', { strictMode: true }) // → false (unexpected!) // Right: specify the format you're validating isDate('2024-01-15', { strictMode: true, format: 'YYYY-MM-DD' }) // → true isDate('2024/01/15', { strictMode: true }) // → true (matches default) isDate('01/15/2024', { strictMode: true, format: 'MM/DD/YYYY' }) // → true Note: isISO8601() with { strict: true } is often more appropriate for ISO 8601 date validation in API contexts.costlowin prodsilent failureusers seelost datavisibilitysilent
- isIBAN · iban-format-only-not-account-verifiederrorWhenisIBAN() used as the sole validation before initiating a bank transfer or payment. isIBAN() validates that the IBAN string follows the correct country-specific format and passes the mod-97 checksum. However, it CANNOT verify that the account exists, is active, belongs to the expected recipient, or is accepting transfers. A correctly formatted IBAN with a valid checksum may belong to a closed account, wrong recipient, or be a sophisticated fraud attempt using a structurally valid but non-existent IBAN (crafted to pass mod-97).Returnstrue for structurally valid IBANs that pass the mod-97 checksum. Does not confirm account existence or ownership.Required handlingUse isIBAN() only as a client-side format check to give early feedback to users. Never use it as the sole validation before payment execution. Always submit IBANs to the payment provider (Stripe, SEPA, SWIFT) for actual account validation. // Client-side UX feedback only if (!isIBAN(ibanInput)) { return { error: 'Invalid IBAN format — check and re-enter' }; } // Backend: must still verify with payment provider await paymentProvider.validateBankAccount({ iban: ibanInput });costhighin prodsilent failureusers seelost transactionvisibilitysilent
- isIBAN · iban-whitespace-stripping-silentwarningWhenisIBAN() used to normalize IBANs for storage, expecting that formatted IBANs with spaces (e.g. 'DE89 3704 0044 0532 0130 00' from paper/UI copy-paste) will be rejected. The default behavior strips whitespace during checksum validation, so formatted IBANs with spaces return true even without allowWhitespace option. Code that expects isIBAN() to reject space-containing IBANs will silently store un-normalized IBANs with spaces in the database.Returnstrue for space-formatted IBANs like 'DE89 3704 0044 0532 0130 00' — the spaces are stripped during checksum verification, not validated as part of format. This means the caller's database may store IBANs with inconsistent spacing.Required handlingAlways normalize IBANs before storage regardless of isIBAN() result: if (!isIBAN(rawIban)) { return res.status(400).json({ error: 'Invalid IBAN' }); } // Normalize: remove all whitespace before storage const normalizedIban = rawIban.replace(/\s+/g, '').toUpperCase(); await db.bankAccounts.create({ iban: normalizedIban }); Use isIBAN(iban, { allowWhitespace: false }) if you want to reject space-formatted IBANs at the input validation stage (forces users to enter compact format).costlowin prodsilent failureusers seelost datavisibilitysilent
- isEmpty · isempty-whitespace-not-empty-by-defaultwarningWhenisEmpty() used to validate required form fields without setting ignore_whitespace: true. The default behavior considers ' ' (spaces only), '\t' (tab), '\n\n' (newlines) as NON-empty strings because their str.length is > 0. A form field filled with only spaces passes isEmpty() check with default options, bypassing required-field validation and potentially storing whitespace-only values in the database.Returnsfalse for whitespace-only strings like ' ', '\t', '\r\n' with default options (ignore_whitespace: false). Returns true only if str.length === 0 — an actual empty string with no characters at all.Required handlingFor required-field validation, always set ignore_whitespace: true or trim first: // Wrong: ' ' passes as non-empty (not caught) if (isEmpty(userInput)) { return res.status(400).json({ error: 'Name is required' }); } // Right: whitespace-only strings caught as empty if (isEmpty(userInput, { ignore_whitespace: true })) { return res.status(400).json({ error: 'Name is required' }); } // Alternative: trim first, then check if (isEmpty(userInput.trim())) { return res.status(400).json({ error: 'Name is required' }); } Note: trimming then storing vs storing then trimming are different behaviors. The trim-first pattern is usually safer for downstream consumers.costmediumin prodsilent failureusers seelost datavisibilitysilent
- isFloat · isfloat-invalid-locale-silent-falseerrorWhenisFloat() called with options.locale set to an unsupported locale string (not in the supported set of ~46 locales listed in validator.isFloatLocales). Unlike isDecimal() which throws an Error for invalid locales, isFloat() silently uses 'undefined' as the decimal separator character in the regex. The resulting regex never matches any real float string, so all validations return false regardless of input. There is no error thrown — the function appears to work but silently rejects all valid float strings.Returnsfalse for ALL input strings when locale is unsupported, because the regex `(?:\undefined[0-9]*)` never matches a real decimal point. The function does not throw. This is a silent wholesale validation failure.Required handlingValidate locale before using it, or use the exported isFloatLocales list: import { isFloat, isFloatLocales } from 'validator'; // Check if locale is supported const safeLocale = isFloatLocales.includes(userLocale) ? userLocale : 'en-US'; isFloat(amountStr, { locale: safeLocale }); // Or: omit locale and normalize input yourself const normalized = amountStr.replace(',', '.'); isFloat(normalized); // Uses default '.' separator Note: isDecimal() throws on invalid locale (easier to catch) while isFloat() silently returns false (harder to detect). If locale detection matters, prefer isDecimal() for monetary amounts.costmediumin prodsilent failureusers seelost datavisibilitysilent
- isFloat · isfloat-locale-comma-replace-asymmetrywarningWhenisFloat() used with a comma-decimal locale (de-DE, fr-FR, ru-RU, etc.) combined with thousands-separator formatted numbers. The function calls parseFloat(str.replace(',', '.')) to compute the numeric value for min/max range comparison — always replacing the FIRST comma with a dot regardless of locale. For European-formatted numbers like '1.234,56' (dot thousands + comma decimal), replace(',', '.') produces '1.234.56' and parseFloat stops at the second dot, returning 1.234 instead of 1234.56. However, the regex test also rejects such numbers (it expects exactly one decimal separator), so the bug only matters if the caller pre-processes the thousands separator but not the decimal.ReturnsFor numbers with thousands separators like '1.234,56' (de-DE format): regex test fails → returns false. The caller must strip thousands separators first. For '1234,56' with locale 'de-DE': test passes, value = 1234.56 — correct. The comma-replace behavior causes incorrect range comparison only when thousands separators are removed but decimal comma is kept AND the value exceeds ranges.Required handlingAlways strip thousands separators before calling isFloat() in locales that use them: // Germany: '1.234,56' (thousands dot, decimal comma) const stripped = rawInput.replace(/\./g, ''); // remove thousands sep isFloat(stripped, { locale: 'de-DE', min: 0 }) // '1234,56' → 1234.56 Or use isCurrency() which has explicit thousands_separator and decimal_separator options designed for locale-aware monetary input validation.costlowin prodsilent failureusers seelost datavisibilitysilent
- isHash · ishash-unknown-algorithm-silent-falseerrorWhenisHash() called with an algorithm string not in the supported set of 13 algorithms. Common mistakes include using dashes ('sha-256' instead of 'sha256'), wrong casing ('SHA256' instead of 'sha256'), or abbreviated names ('sha2'). When the algorithm is unknown, lengths[algorithm] is undefined, the regex becomes `^[a-fA-F0-9]{undefined}$` which never matches any hex string. All hash validations silently return false — allowing any input string (including malicious non-hash values) to bypass hash format validation.Returnsfalse for ALL input strings (including valid hash strings) when algorithm is unknown or misspelled. The function does not throw. Security checks that rely on isHash() for input validation are silently bypassed entirely.Required handlingUse exact lowercase algorithm names from the documented set: // Wrong: common typos isHash(value, 'SHA256') // returns false for all input isHash(value, 'sha-256') // returns false for all input isHash(value, 'sha2') // returns false for all input isHash(value, 'ripemd-128') // returns false for all input // Right: exact documented names isHash(value, 'sha256') // validates 64-char hex isHash(value, 'sha512') // validates 128-char hex isHash(value, 'md5') // validates 32-char hex isHash(value, 'ripemd128') // validates 32-char hex To defensively validate the algorithm name: const VALID_ALGORITHMS = ['md5', 'md4', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']; if (!VALID_ALGORITHMS.includes(algorithm)) { throw new Error(`Unsupported hash algorithm: ${algorithm}`); } if (!isHash(hashValue, algorithm)) { return res.status(400).json({ error: 'Invalid hash format' }); }costhighin prodsilent failureusers seesecurity breachvisibilitysilent
- isIn · isin-undefined-values-silent-falseerrorWhenisIn() called where the values/allowlist parameter is undefined, null, or a variable that wasn't populated (e.g., permissions array from a failed DB query, config not yet loaded, or undefined roles list). When the values argument is undefined or null, none of the array/object/string branches execute and the function returns false without throwing. Code that uses isIn() for role-based access control or input allowlisting will silently deny ALL values when the allowlist is missing — either blocking all users (denial of service) or silently passing all users through (if the result is negated for "not in blocked list").Returnsfalse for ALL str values when values parameter is undefined or null. No TypeError, no Error — the function returns as if the string is not in the (missing) set. isIn('admin', undefined) === false, isIn('user', null) === false.Required handlingGuard against undefined/null allowlists before calling isIn(): // Wrong: if allowedRoles is undefined, all users are silently denied if (!isIn(user.role, allowedRoles)) { return res.status(403).json({ error: 'Access denied' }); } // Right: validate the allowlist exists before use if (!Array.isArray(allowedRoles) || allowedRoles.length === 0) { throw new Error('Permission configuration error: allowedRoles not configured'); } if (!isIn(user.role, allowedRoles)) { return res.status(403).json({ error: 'Access denied' }); } // Alternative: use native Array.includes() which throws on null/undefined // making misconfiguration visible as an error rather than a silent false if (!allowedRoles.includes(user.role)) { ... }costhighin prodsilent failureusers seesecurity breachvisibilitysilent
- isBoolean · isboolean-strict-accepts-zero-onewarningWhenisBoolean() used in strict mode (default) to validate that user input is a 'true'/'false' boolean string, where the downstream consumer converts using `value === 'true'` or JSON.parse(). The strict mode accepts '0' and '1' as valid boolean strings. If a user submits '1' (a common boolean representation in HTML forms, query strings, and some APIs), isBoolean() passes it, but downstream code using `value === 'true'` treats '1' as false, silently inverting the boolean for feature flags, consent checkboxes, or notification preferences.Returnstrue for '0', '1', 'true', 'false' in strict mode (default). true for '0', '1', 'true', 'false', 'yes', 'no', 'YES', 'NO', 'True', 'False' in loose mode. Returns false for 'on', 'off', 'enabled', 'disabled', 'y', 'n' — in BOTH modes.Required handlingBe explicit about the boolean format your API accepts and how you convert it: // If you only want 'true'/'false' (e.g., JSON API): if (!['true', 'false'].includes(input)) { return res.status(400).json({ error: 'Must be "true" or "false"' }); } const boolValue = input === 'true'; // If you accept HTML checkbox values '0'/'1': if (!isBoolean(input)) { ... } // '0' and '1' accepted const boolValue = input === '1' || input === 'true'; // If you want human-readable ('yes'/'no' from forms): if (!isBoolean(input, { loose: true })) { ... } const boolValue = ['true', '1', 'yes'].includes(input.toLowerCase()); Document which boolean format your endpoint accepts — '0'/'1' vs 'true'/'false' vs 'yes'/'no' are three different contracts that isBoolean() partially overlaps.costlowin prodsilent failureusers seelost datavisibilitysilent
- isNumeric · isnumeric-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingCaller MUST ensure str is a string before calling isNumeric(). Sources like req.query or parsed form fields may deliver numbers or null at runtime. Unguarded calls crash the request handler.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - isNumeric · isnumeric-invalid-locale-silent-mismatchwarningWhenoptions.locale set to an unsupported locale codeReturnsincorrect boolean — valid decimals may fail; invalid strings may passRequired handlingWhen options.locale is set, it must be a code from validator's supported list (e.g. 'en-US', 'de-DE', 'ar', 'bg-BG', 'fr-CA'). An unrecognised locale makes alpha.decimal[locale] return undefined, producing a regex that tests for the literal string "undefined" as a decimal separator. Validation results become silently incorrect. Use isLocale() to validate the locale before passing it to isNumeric(), or hardcode only supported locale strings.costlowin prodsilent failureusers seelost datavisibilitysilent
- isInt · isint-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingCaller MUST ensure str is a string. Integer fields from JSON bodies, URL params, or DB queries can arrive as actual number types. Passing a number directly throws. Wrap in String() before calling or guard with typeof.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - isInt · isint-range-returns-false-not-throwwarningWhenvalue is a valid integer but outside min/max/lt/gt boundsReturnsfalse — no exception thrownRequired handlingisInt(str, { min: 1, max: 100 }) returns false for '0' or '101' without throwing. Callers that only check !isInt(...) without acting on the false return silently accept out-of-range values. Always check the return value and reject accordingly — do NOT use isInt() as a guard without checking the result.costlowin prodsilent failureusers seelost datavisibilitysilentSources[50]
- equals · equals-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingCaller MUST ensure str is a string. In token comparison flows, the token from req.headers or a DB query may be null/undefined if the auth header is missing. Passing null throws, crashing the authentication check. If the catch block is too broad it may inadvertently allow the request through.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - contains · contains-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingCaller MUST ensure str is a string. Form fields and query params may be null or undefined when optional. Unguarded calls to contains() in content-filter middleware crash the request handler.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10] - contains · contains-unchecked-return-security-bypasswarningWhenreturn value not checked — used as security or content gateReturnsfalse when str does not contain seedRequired handlingcontains() returns false when the substring is absent — it does NOT throw. Code that calls contains() for a required security check (e.g. confirming a nonce is present in a signed payload) and ignores the return value silently passes malformed inputs. Always check the boolean result and reject immediately when false.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[51]
- isAfter · isafter-unparseable-date-returns-falsewarningWheneither date string cannot be parsed (invalid format, null, garbage)Returnsfalse — no exception thrownRequired handlingisAfter(str) returns false both when the date is genuinely before the comparison date AND when the date string is unparseable. Code that only checks !isAfter(userDate) to enforce a future-date requirement silently accepts garbage strings ('not-a-date', '99-99-9999') because they also return false. Pair with isDate() or isISO8601() first to confirm the string is a valid date, then use isAfter() for the range check.costlowin prodsilent failureusers seelost datavisibilitysilentSources[52]
- isBefore · isbefore-unparseable-date-returns-falsewarningWheneither date string cannot be parsedReturnsfalse — no exception thrownRequired handlingisBefore(str) returns false both when the date is genuinely after the comparison date AND when the date string is invalid. Subscription expiry checks that use isBefore(expiryDate) silently treat garbage expiry strings as "not yet expired", granting perpetual access. Pair with isDate() or isISO8601() before using isBefore() for access-control decisions.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[53]
- ltrim · ltrim-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingCaller MUST ensure str is a string. ltrim() is used in sanitisation pipelines where the input may be null/undefined from optional form fields or query params. Unlike JavaScript's built-in String.prototype.trimStart(), validator's ltrim() throws rather than coercing — passing null crashes.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - rtrim · rtrim-non-string-typeerrorerrorWhennon-string value passed as str argumentThrows
TypeError: Expected a string but received a <type>Required handlingSame contract as ltrim(). Caller MUST ensure str is a string. rtrim() throws rather than coercing — null/undefined input from optional form fields crashes the sanitisation step. Guard with typeof before calling.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - isBase58 · base58-format-only-not-checksummederrorWhenisBase58() used to validate Bitcoin, Litecoin, Solana, or IPFS addressesReturnstrue for any Base58 character-set string, including corrupted/fabricated addressesRequired handlingCRITICAL: isBase58() only checks the character alphabet — it does NOT verify the Base58Check 4-byte checksum embedded in Bitcoin P2PKH ('1...') and P2SH ('3...') addresses. A typo in a Bitcoin address (e.g. last character changed from 'y' to 'Z') still passes isBase58() because both characters are in the Base58 alphabet. Do NOT use isBase58() alone to validate cryptocurrency wallet addresses before sending funds. Use a chain-specific library (bitcoinjs-lib, ethers, @solana/web3.js) that performs full address validation including checksum and checksum-decode steps. isBase58() is safe only as a lightweight pre-filter before full validation. For IPFS CIDs (content-addressed Base58-encoded multihashes), isBase58() is also insufficient — IPFS CIDv0 hashes are 46-char Base58 strings starting with 'Qm'; character-set checking does not verify the multihash structure.costhighin prodsilent failureusers seelost datavisibilitysilent
- isBase58 · base58-empty-string-validwarningWhenisBase58('') used as truthy guard for non-empty inputReturnstrue for empty string ''Required handlingisBase58() uses regex /^[A-HJ-NP-Za-km-z1-9]*$/ — the * quantifier means empty string passes. An empty wallet address or IPFS CID passes the check. Always pair with a length/non-empty guard: if (str && str.length > 0 && isBase58(str)) { ... } A missing or empty address field silently passes isBase58('') validation.costmediumin prodsilent failureusers seelost datavisibilitysilentSources[55]
- isBase58 · base58-non-string-typeerrorerrorWhennon-string value passed as str argument (null, undefined, number)Throws
TypeError: Expected a string but received a <type>Required handlingisBase58() calls assertString() which throws TypeError for null, undefined, or non-string input. Wallet addresses from API responses or form fields may be null/undefined when missing. Guard with typeof check: if (typeof address === 'string' && isBase58(address)) { ... }costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[10]
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]owasp.org/www-community/attackshttps://owasp.org/www-community/attacks/xss/
- [2]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/issues/1089
- [3]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js#sanitizers
- [4]npmjs.com/package/validatorhttps://www.npmjs.com/package/validator
- [5]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js#validators
- [6]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/security/advisories/GHSA-9965-vmph-33xx
- [7]github.com/advisories/GHSA-9965-vmph-33xxhttps://github.com/advisories/GHSA-9965-vmph-33xx
- [8]developer.mozilla.org/en-US/docshttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#exceptions
- [9]pages.nist.gov/800-63-3/sp800-63b.htmlhttps://pages.nist.gov/800-63-3/sp800-63b.html
- [10]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/util/assertString.js
- [11]owasp.org/www-project-web-security-testing-guide/latesthttps://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/10-Testing_JSON_Web_Tokens
- [12]developer.mozilla.org/en-US/docshttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#date_time_string_format
- [13]developer.mozilla.org/en-US/docshttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#radix
- [14]stripe.com/docs/testinghttps://stripe.com/docs/testing#cards
- [15]owasp.org/www-community/attackshttps://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- [16]datatracker.ietf.org/doc/htmlhttps://datatracker.ietf.org/doc/html/rfc4648#section-5
- [17]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isBase64.js
- [18]unicode.org/faq/utf_bom.htmlhttps://unicode.org/faq/utf_bom.html#utf16-2
- [19]datatracker.ietf.org/doc/htmlhttps://datatracker.ietf.org/doc/html/rfc3339
- [20]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isLicensePlate.js
- [21]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isBase32.js
- [22]crockford.com/base32.htmlhttps://www.crockford.com/base32.html
- [23]github.com/ulid/spechttps://github.com/ulid/spec
- [24]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isMobilePhone.js
- [25]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isPostalCode.js
- [26]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isTaxID.js
- [27]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isVAT.js
- [28]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isIdentityCard.js
- [29]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/unescape.js
- [30]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/blacklist.js
- [31]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/whitelist.js
- [32]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/toBoolean.js
- [33]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/trim.js
- [34]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/ltrim.js
- [35]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isByteLength.js
- [36]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isWhitelisted.js
- [37]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isAlpha.js
- [38]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isAlphanumeric.js
- [39]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isDecimal.js
- [40]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isDate.js
- [41]en.wikipedia.org/wiki/International_Bank_Account_Numberhttps://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
- [42]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isIBAN.js
- [43]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isEmpty.js
- [44]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isFloat.js
- [45]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isHash.js
- [46]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isIn.js
- [47]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isBoolean.js
- [48]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isNumeric.js
- [49]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/alpha.js
- [50]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isInt.js
- [51]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/contains.js
- [52]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isAfter.js
- [53]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isBefore.js
- [54]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/rtrim.js
- [55]github.com/validatorjs/validator.jshttps://github.com/validatorjs/validator.js/blob/master/src/lib/isBase58.js
- [56]en.bitcoin.it/wiki/Base58Check_encodinghttps://en.bitcoin.it/wiki/Base58Check_encoding
Need a different package?
Request a profile