From e9534e12a0b070375200f8634b0a7bb72d36a6a8 Mon Sep 17 00:00:00 2001 From: Minjung Date: Mon, 2 Nov 2026 09:08:00 +0900 Subject: [PATCH] fix: treat custom trim hyphens as literal characters --- README.md | 6 +++--- src/lib/ltrim.js | 2 +- src/lib/rtrim.js | 2 +- test/sanitizers.test.js | 12 ++++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e8b7aedd9..0f57d8a99 100644 --- a/README.md +++ b/README.md @@ -183,16 +183,16 @@ Sanitizer | Description -------------------------------------- | ------------------------------- **blacklist(input, chars)** | remove characters that appear in the blacklist. The characters are used in a RegExp and so you will need to escape some chars, e.g. `blacklist(input, '\\[\\]')`. **escape(input)** | replace `<`, `>`, `&`, `'`, `"`, `` ` ``, `\` and `/` with HTML entities. -**ltrim(input [, chars])** | trim characters from the left-side of the input. +**ltrim(input [, chars])** | trim characters from the left-side of the input. `chars` specifies literal characters, not regular expression ranges. **normalizeEmail(email [, options])** | canonicalize an email address. (This doesn't validate that the input is an email, if you want to validate the email use isEmail beforehand).

`options` is an object with the following keys and default values:
-**rtrim(input [, chars])** | trim characters from the right-side of the input. +**rtrim(input [, chars])** | trim characters from the right-side of the input. `chars` specifies literal characters, not regular expression ranges. **stripLow(input [, keep_new_lines])** | remove characters with a numerical value < 32 and 127, mostly control characters. If `keep_new_lines` is `true`, newline characters are preserved (`\n` and `\r`, hex `0xA` and `0xD`). Unicode-safe in JavaScript. **toBoolean(input [, strict])** | convert the input string to a boolean. Everything except for `'0'`, `'false'` and `''` returns `true`. In strict mode only `'1'` and `'true'` return `true`. **toDate(input)** | convert the input string to a date, or `null` if the input is not a date. **toFloat(input)** | convert the input string to a float, or `NaN` if the input is not a float. **toInt(input [, radix])** | convert the input string to an integer, or `NaN` if the input is not an integer. **toString(input)** | convert the input to a string. `null`, `undefined` and `NaN` are converted to an empty string, and objects are converted using their own `toString` method. -**trim(input [, chars])** | trim characters (whitespace by default) from both sides of the input. +**trim(input [, chars])** | trim characters (whitespace by default) from both sides of the input. `chars` specifies literal characters, not regular expression ranges. **unescape(input)** | replace HTML encoded entities with `<`, `>`, `&`, `'`, `"`, `` ` ``, `\` and `/`. **whitelist(input, chars)** | remove characters that do not appear in the whitelist. The characters are used in a RegExp and so you will need to escape some chars, e.g. `whitelist(input, '\\[\\]')`. diff --git a/src/lib/ltrim.js b/src/lib/ltrim.js index 372d2df8e..3d995426b 100644 --- a/src/lib/ltrim.js +++ b/src/lib/ltrim.js @@ -3,6 +3,6 @@ import assertString from './util/assertString'; export default function ltrim(str, chars) { assertString(str); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping - const pattern = chars ? new RegExp(`^[${chars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]+`, 'g') : /^\s+/g; + const pattern = chars ? new RegExp(`^[${chars.replace(/[-.*+?^${}()|[\]\\]/g, '\\$&')}]+`, 'g') : /^\s+/g; return str.replace(pattern, ''); } diff --git a/src/lib/rtrim.js b/src/lib/rtrim.js index 2d311574b..6b4219660 100644 --- a/src/lib/rtrim.js +++ b/src/lib/rtrim.js @@ -4,7 +4,7 @@ export default function rtrim(str, chars) { assertString(str); if (chars) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping - const pattern = new RegExp(`[${chars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]+$`, 'g'); + const pattern = new RegExp(`[${chars.replace(/[-.*+?^${}()|[\]\\]/g, '\\$&')}]+$`, 'g'); return str.replace(pattern, ''); } // Use a faster and more safe than regex trim method https://blog.stevenlevithan.com/archives/faster-trim-javascript diff --git a/test/sanitizers.test.js b/test/sanitizers.test.js index 5f6454afb..361686e0d 100644 --- a/test/sanitizers.test.js +++ b/test/sanitizers.test.js @@ -121,6 +121,18 @@ describe('Sanitizers', () => { }); }); + [ + { sanitizer: 'ltrim', expect: { '--azhello': 'hello', hello: 'hello' } }, + { sanitizer: 'rtrim', expect: { 'helloza--': 'hello', hello: 'hello' } }, + { sanitizer: 'trim', expect: { '--azhelloza--': 'hello', hello: 'hello' } }, + ].forEach(({ sanitizer, expect }) => { + it(`should trim literal hyphens with ${sanitizer}`, () => { + ['a-z', 'z-a'].forEach((chars) => { + test({ sanitizer, args: [chars], expect }); + }); + }); + }); + it('should convert strings to integers', () => { test({ sanitizer: 'toInt',