From ba2b9fb6805f71784f9274e6602b73a68e61cf62 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 30 Sep 2026 09:07:49 +0700 Subject: [PATCH 1/2] fix: reject malformed alias tags --- entrypoints/popup/utils.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/entrypoints/popup/utils.ts b/entrypoints/popup/utils.ts index c1fd4f09..aa9af8d6 100644 --- a/entrypoints/popup/utils.ts +++ b/entrypoints/popup/utils.ts @@ -56,12 +56,26 @@ export function filterAliasesForAccount( /** Creates a plus-addressed alias (user+tag@domain), or null if the base email is malformed. */ export function generateAlias(baseEmail: string, tag: string): string | null { - const parts = baseEmail.trim().split("@"); + const normalizedEmail = baseEmail.trim(); + const normalizedTag = tag.trim(); + const parts = normalizedEmail.split("@"); if (parts.length !== 2) return null; const [username, domain] = parts; - if (!username || !domain) return null; - return `${username}+${tag}@${domain}`; + if (!username || !domain || !domain.includes(".")) return null; + + // A plus tag becomes part of the email local-part. Whitespace, an @ sign, + // or control characters would create an address that cannot be safely used + // in forms and could also introduce a second domain separator. + if ( + !normalizedTag || + /[\\s@]/.test(normalizedTag) || + /[\\u0000-\\u001f\\u007f]/.test(normalizedTag) + ) { + return null; + } + + return `${username}+${normalizedTag}@${domain}`; } export type RandomFormat = From 637e14885370ce616c9976575d9b687ea2aefac7 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 30 Sep 2026 09:07:51 +0700 Subject: [PATCH 2/2] test: cover malformed alias generation --- tests/popup/utils.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/popup/utils.test.ts b/tests/popup/utils.test.ts index c36ee7e5..ff095e32 100644 --- a/tests/popup/utils.test.ts +++ b/tests/popup/utils.test.ts @@ -160,6 +160,28 @@ describe("generateAlias", () => { "user+private-mail-abc1@gmail.com", ); }); + + it("trims surrounding whitespace from tags", () => { + expect(generateAlias("user@gmail.com", " shopping ")).toBe( + "user+shopping@gmail.com", + ); + }); + + it("rejects an empty tag", () => { + expect(generateAlias("user@gmail.com", " ")).toBeNull(); + }); + + it("rejects tags containing whitespace", () => { + expect(generateAlias("user@gmail.com", "project alpha")).toBeNull(); + }); + + it("rejects tags containing an @ sign", () => { + expect(generateAlias("user@gmail.com", "shop@example.com")).toBeNull(); + }); + + it("rejects a base email without a routable domain", () => { + expect(generateAlias("user@localhost", "tag")).toBeNull(); + }); }); // ─── generateRandomString ────────────────────────────────────────────────────