fix(security): quoted local-part email mask — strip delimiter quotes, split on last @ (DC-109) [glm-grade=A]
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

This commit is contained in:
Hermes
2026-08-23 07:28:10 -07:00
parent c429b8fdd7
commit 9322831f1b
3 changed files with 50 additions and 3 deletions
+13 -2
View File
@@ -85,9 +85,20 @@ function formatTime() {
const EMAIL_RE = /(?:[A-Za-z0-9._%+-]{1,64}|"[^"\n\\]{1,64}")@[A-Za-z0-9.-]{0,253}\.[A-Za-z]{2,24}/g;
function maskEmailAddress(addr) {
const at = addr.indexOf('@');
const local = addr.slice(0, at);
// addr is always a full EMAIL_RE match. Quoted local-parts (RFC 5322) match
// WITH their delimiter quotes and may contain '@' inside the quotes, so
// split on the LAST '@' (the real domain boundary), never the first.
// The quotes are syntax, not PII: strip them before masking and never
// re-emit them — slice(0, 2) of '"john doe"@…' used to leave a stray
// unbalanced quote in the output that could glue onto later text and
// re-match EMAIL_RE on a second pass (DC-109).
const at = addr.lastIndexOf('@');
let local = addr.slice(0, at);
const domain = addr.slice(at);
if (local.length >= 2 && local.startsWith('"') && local.endsWith('"')) {
local = local.slice(1, -1);
}
if (local.length === 0) return '****' + domain;
if (local.length <= 2) return local[0] + '****' + domain;
return local.slice(0, 2) + '****' + domain;
}