From b093237da071d4cfea26bc488adb9b497c0b1b26 Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 12 Sep 2026 11:35:03 +0900 Subject: [PATCH] fix(normalize-color): require full-string match for rgb/hsl/hwb Functional color regexes lacked ^/$, so junk around a valid rgb()/hsl()/hwb() substring was accepted while hex forms already required a full match. --- .../__tests__/normalizeColor-test.js | 7 +++++++ packages/normalize-color/index.js | 16 +++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/normalize-color/__tests__/normalizeColor-test.js b/packages/normalize-color/__tests__/normalizeColor-test.js index 95a26a415ec9..46313631f005 100644 --- a/packages/normalize-color/__tests__/normalizeColor-test.js +++ b/packages/normalize-color/__tests__/normalizeColor-test.js @@ -37,6 +37,13 @@ it('refuses non-spec compliant colors', () => { expect(normalizeColor('#00gg00')).toBe(null); expect(normalizeColor('rgb(1, 2, 3,)')).toBe(null); expect(normalizeColor('rgb(1, 2, 3')).toBe(null); + // Functional forms must match the whole string (hex already did). + expect(normalizeColor('xxrgb(1, 2, 3)yy')).toBe(null); + expect(normalizeColor('rgb(1, 2, 3)yy')).toBe(null); + expect(normalizeColor('xxrgb(1, 2, 3)')).toBe(null); + expect(normalizeColor('rgba(1,2,3,0.5)extra')).toBe(null); + expect(normalizeColor('prefixhsl(0, 0%, 0%)')).toBe(null); + expect(normalizeColor('hwb(0 0% 0%)suffix')).toBe(null); // Used to be accepted by normalizeColor expect(normalizeColor('abc')).toBe(null); diff --git a/packages/normalize-color/index.js b/packages/normalize-color/index.js index 05bdc3adc93e..6ff8ff0c79c4 100644 --- a/packages/normalize-color/index.js +++ b/packages/normalize-color/index.js @@ -276,23 +276,25 @@ function getMatchers() { '|' + callWithSlashSeparator(NUMBER, NUMBER, NUMBER, NUMBER); + // Anchor functional forms the same way as hex* so leading/trailing + // junk (e.g. "xxrgb(1, 2, 3)yy") cannot partially match. cachedMatchers = { - rgb: new RegExp('rgb(' + rgbRegexPattern + ')'), - rgba: new RegExp('rgba(' + rgbRegexPattern + ')'), - hsl: new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE)), + rgb: new RegExp('^rgb(' + rgbRegexPattern + ')$'), + rgba: new RegExp('^rgba(' + rgbRegexPattern + ')$'), + hsl: new RegExp('^hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE) + '$'), hsla: new RegExp( - 'hsla(' + + '^hsla(' + commaSeparatedCall(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER) + '|' + callWithSlashSeparator(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER) + - ')', + ')$', ), hwb: new RegExp( - 'hwb(' + + '^hwb(' + callModern(NUMBER, PERCENTAGE, PERCENTAGE) + '|' + callWithSlashSeparator(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER) + - ')', + ')$', ), hex3: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, hex4: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,