Secure Character Ranges for Lodash trimEnd
This article explores how Lodash’s _.trimEnd processes
string suffixes, detailing the exact Unicode whitespace ranges the
function targets by default and the explicit character ranges required
to safely validate dynamic suffix patterns. Readers will learn the
internal mechanisms of Lodash’s trimming logic, how to prevent regular
expression injection vulnerabilities during dynamic suffix checks, and
how to reliably model suffix boundaries across ASCII and Unicode
character sets.
Understanding Lodash
_.trimEnd Mechanics
The _.trimEnd method strips trailing characters from a
target string. When invoked with only a string argument
(_.trimEnd(string)), Lodash defaults to stripping all
trailing ECMAScript and Unicode whitespace characters. When invoked with
a custom character set (_.trimEnd(string, [chars])), Lodash
dynamically interprets those characters as a discrete collection of
single-character symbols to match and remove from the end of the
string.
Internally, Lodash converts the chars argument into an
array of characters—handling astral plane Unicode characters (surrogate
pairs) correctly—and compiles or iterates these characters against the
end of the string until a non-matching character is encountered.
Default Unicode Whitespace Character Ranges
When no custom characters are passed, Lodash targets standard ECMAScript whitespace and line terminator code points. To validate or mirror this behavior using explicit character classes, you must account for the following explicit hex and Unicode ranges:
- ASCII Whitespace and Control Codes:
- Tabulation:
\u0009(\t) - Line Feed:
\u000A(\n) - Vertical Tab:
\u000B(\v) - Form Feed:
\u000C(\f) - Carriage Return:
\u000D(\r) - Space:
\u0020
- Tabulation:
- Latin-1 Supplement Whitespace:
- No-Break Space:
\u00A0
- No-Break Space:
- Ogham Space Mark:
\u1680
- General Punctuation Space Separators (En quad to Hair
space):
- Range:
\u2000through\u200A
- Range:
- Line and Paragraph Separators:
- Line Separator:
\u2028 - Paragraph Separator:
\u2029
- Line Separator:
- Additional Unicode Spaces:
- Narrow No-Break Space:
\u202F - Medium Mathematical Space:
\u205F - Ideographic Space (CJK):
\u3000
- Narrow No-Break Space:
- Zero Width No-Break Space (Byte Order Mark):
\uFEFF
Expressed as a single explicit regular expression character class, this complete range is:
[\t\n\v\f\r \u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]
Explicit Ranges for Dynamic Suffix Validation
When validating inputs dynamically modified by
_.trimEnd(str, dynamicChars), treating user-defined
suffixes blindly can introduce Regular Expression Denial of Service
(ReDoS) or syntax corruption. Securely validating dynamic suffix
boundaries requires bounding inputs to explicit, well-defined
ranges:
1. Printable ASCII Range
(\x20-\x7E)
If suffixes are strictly alphanumeric or standard punctuation, validate that dynamic inputs fall entirely within the standard printable ASCII range:
- Range:
^[\x20-\x7E]+$This prevents control characters (\x00-\x1F,\x7F) from altering string parsing or introducing invisible suffixes.
2. Unicode Identifier Ranges
When suffixes represent code tokens, variable names, or natural
language, use Unicode property escapes (\p{L},
\p{N}, \p{P}) with the u
flag:
- Safe Character Set:
^[\p{Letter}\p{Number}\p{Punctuation}\s]+$uThis ensures only visible, structurally valid characters enter dynamic suffix trimming logic.
3. Escaped Dynamic Literal Validation
If custom suffixes are dynamically injected into regular expressions
to verify what _.trimEnd would remove, special regular
expression control characters must be escaped:
- Reserved characters requiring escape:
[\^$.*+?()[{\|] - Safe construction pattern:
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const safeChars = escapeRegExp(dynamicChars); const suffixValidator = new RegExp(`[${safeChars}]+$`, 'u');
Security Best Practices for Suffix Normalization
- Avoid Unbounded Regex Compilation: Do not pass
unvalidated user input directly into
RegExpconstructors alongside anchor symbols ($or\b). Rely on_.trimEnddirectly or escape inputs before constructing dynamic expressions. - Surrogate Pair Awareness: Lodash handles astral
code points (e.g., emojis in the
\uD800-\uDFFFsurrogate ranges). If using explicit ranges to validate Lodash's output, ensure your regular expressions include the Unicode (u) flag to prevent split surrogate pairs. - Immutability of Suffix Sets: Enforce explicit
whitelists of acceptable characters (such as
[a-zA-Z0-9_-]) before allowing dynamic suffix-stripping in security-sensitive contexts, such as sanitizing file names, URIs, or database keys.