From ab967e2a64cd3cd63aa863920b6e232a344d1a4e Mon Sep 17 00:00:00 2001 From: yfwmaniish Date: Sun, 6 Sep 2026 22:58:40 +0530 Subject: [PATCH 1/2] fix(isFloat): fall back to '.' separator for an unknown locale --- src/lib/isFloat.js | 5 ++++- test/validators.test.js | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib/isFloat.js b/src/lib/isFloat.js index 84bdc782c..5eeb9f511 100644 --- a/src/lib/isFloat.js +++ b/src/lib/isFloat.js @@ -5,7 +5,10 @@ import { decimal } from './alpha'; export default function isFloat(str, options) { assertString(str); options = options || {}; - const float = new RegExp(`^(?:[-+])?(?:[0-9]+)?(?:\\${options.locale ? decimal[options.locale] : '.'}[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$`); + // Fall back to `.` when the locale is unknown; otherwise `decimal[locale]` + // is `undefined` and stringifies into the pattern as the literal `undefined`. + const decimalSeparator = decimal[options.locale] || '.'; + const float = new RegExp(`^(?:[-+])?(?:[0-9]+)?(?:\\${decimalSeparator}[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$`); if (str === '' || str === '.' || str === ',' || str === '-' || str === '+') { return false; } diff --git a/test/validators.test.js b/test/validators.test.js index 98d2a12ff..035611dc6 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -4857,6 +4857,23 @@ describe('Validators', () => { 'foo', ], }); + test({ + validator: 'isFloat', + args: [{ + locale: 'is-NOT-a-locale', + }], + valid: [ + '123', + '123.123', + '-3.5e2', + ], + invalid: [ + '3undefined5', + '123,123', + 'foo', + '', + ], + }); test({ validator: 'isFloat', args: [{ From f3355718020ef3addf989727617baa65105f03e2 Mon Sep 17 00:00:00 2001 From: yfwmaniish Date: Tue, 8 Sep 2026 13:17:32 +0530 Subject: [PATCH 2/2] fix(isFloat): guard the locale lookup with hasOwnProperty for inherited names --- src/lib/isFloat.js | 10 +++++++--- test/validators.test.js | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/lib/isFloat.js b/src/lib/isFloat.js index 5eeb9f511..3856d70a1 100644 --- a/src/lib/isFloat.js +++ b/src/lib/isFloat.js @@ -5,9 +5,13 @@ import { decimal } from './alpha'; export default function isFloat(str, options) { assertString(str); options = options || {}; - // Fall back to `.` when the locale is unknown; otherwise `decimal[locale]` - // is `undefined` and stringifies into the pattern as the literal `undefined`. - const decimalSeparator = decimal[options.locale] || '.'; + // Fall back to `.` unless the locale is an own key of `decimal`. Indexing + // `decimal[options.locale]` directly would also match inherited names such as + // `__proto__`, `constructor` or `toString`, whose truthy values leak into the + // pattern (e.g. the separator becomes the literal `[object Object]`). + const decimalSeparator = Object.prototype.hasOwnProperty.call(decimal, options.locale) + ? decimal[options.locale] + : '.'; const float = new RegExp(`^(?:[-+])?(?:[0-9]+)?(?:\\${decimalSeparator}[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$`); if (str === '' || str === '.' || str === ',' || str === '-' || str === '+') { return false; diff --git a/test/validators.test.js b/test/validators.test.js index 035611dc6..b1f8f8400 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -4874,6 +4874,25 @@ describe('Validators', () => { '', ], }); + // Inherited property names (e.g. __proto__, constructor) are not own keys of + // the decimal map, so they must fall back to the "." separator too. + for (const inheritedLocale of ['__proto__', 'constructor', 'toString', 'hasOwnProperty', 'valueOf']) { + test({ + validator: 'isFloat', + args: [{ locale: inheritedLocale }], + valid: [ + '123', + '123.123', + '-3.5e2', + ], + invalid: [ + '123,123', + '3[object Object]5', + 'foo', + '', + ], + }); + } test({ validator: 'isFloat', args: [{