From 94885109fa6e0e44972baed64fb3a16e90ee763a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Feb 2026 21:41:19 -0500 Subject: [PATCH] fix: closes #8642, stricter username check don't allow invisible unicode characters --- public/src/utils.common.js | 7 ++++++- test/utils.js | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/public/src/utils.common.js b/public/src/utils.common.js index fbebb7ba73..2035261755 100644 --- a/public/src/utils.common.js +++ b/public/src/utils.common.js @@ -16,6 +16,8 @@ function replaceChar(c) { } const escapeChars = /[&<>"'`=]/g; +const invisibleChars = /[\u200B-\u200F\u202A-\u202E\u2066-\u2069\u3164\uFEFF]/; + const HTMLEntities = Object.freeze({ amp: '&', gt: '>', @@ -329,7 +331,10 @@ const utils = { }, isUserNameValid: function (name) { - return (name && name !== '' && (/^['" \-+.*[\]0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name))); + if (!name || name === '') return false; + if (name.trim().length === 0) return false; + if (invisibleChars.test(name)) return false; + return (/^['" \-+.*[\]0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name)); }, isPasswordValid: function (password) { diff --git a/test/utils.js b/test/utils.js index cd5ec12a4b..1d801b3338 100644 --- a/test/utils.js +++ b/test/utils.js @@ -91,6 +91,17 @@ describe('Utility Methods', () => { assert.equal(utils.isUserNameValid(username), false, 'accepted as valid username'); }); + it('rejects string with only spaces', () => { + const username = ' '; + assert.equal(utils.isUserNameValid(username), false, 'accepted as valid username'); + }); + + it('rejects string with tabs', () => { + // eslint-disable-next-line @stylistic/js/no-tabs + const username = ' '; + assert.equal(utils.isUserNameValid(username), false, 'accepted as valid username'); + }); + it('should reject new lines', () => { assert.equal(utils.isUserNameValid('myusername\r\n'), false); }); @@ -103,6 +114,11 @@ describe('Utility Methods', () => { assert.equal(utils.isUserNameValid('myusername\t'), false); }); + it('should reject hangul filler U+3164', () => { + assert.equal(utils.isUserNameValid('myusernameㅤ'), false); + assert.equal(utils.isUserNameValid('ㅤㅤㅤ'), false); + }); + it('accepts square brackets', () => { const username = '[best clan] julian'; assert(utils.isUserNameValid(username), 'invalid username');