diff --git a/README.md b/README.md index 751d174..4a0477c 100644 --- a/README.md +++ b/README.md @@ -2659,7 +2659,8 @@ plaintext list of anyone's domain names. When a dApp on a blocklisted domain requests a wallet connection, transaction approval, or signature, the approval popup displays a prominent red warning banner alerting the user. The domain checker matches exact hostnames and all -parent domains (subdomain matching). +parent domains (subdomain matching), and checks a hostname written with a +trailing dot (`name.`) as `name`. #### Transaction Decoding diff --git a/src/shared/phishingDomains.js b/src/shared/phishingDomains.js index 6ecb953..f43f23a 100644 --- a/src/shared/phishingDomains.js +++ b/src/shared/phishingDomains.js @@ -110,11 +110,14 @@ function hashListed(hash) { * Generate hostname variants for subdomain matching. * "sub.evil.com" yields ["sub.evil.com", "evil.com"]. * + * A trailing dot is dropped: "evil.com." is the fully qualified spelling of + * "evil.com", and the browser loads the same site from either. + * * @param {string} hostname * @returns {string[]} */ function hostnameVariants(hostname) { - const h = hostname.toLowerCase(); + const h = hostname.toLowerCase().replace(/\.$/, ""); const variants = [h]; const parts = h.split("."); // Parent domains: a.b.c.d -> b.c.d, c.d diff --git a/tests/phishingDomains.test.js b/tests/phishingDomains.test.js index e203d59..b860053 100644 --- a/tests/phishingDomains.test.js +++ b/tests/phishingDomains.test.js @@ -89,6 +89,12 @@ describe("vendored blocklist", () => { expect(isPhishingDomain(LISTED[0].toUpperCase())).toBe(true); }); + test("a hostname ending in a dot is the same host", () => { + expect(isPhishingDomain(LISTED[1] + ".")).toBe(true); + expect(isPhishingDomain("wallet." + LISTED[1] + ".")).toBe(true); + expect(isPhishingDomain(CLEAN[0] + ".")).toBe(false); + }); + test("returns false for an empty or missing hostname", () => { expect(isPhishingDomain("")).toBe(false); expect(isPhishingDomain(null)).toBe(false); @@ -133,6 +139,13 @@ describe("hostnameVariants", () => { test("lowercases hostnames", () => { expect(hostnameVariants("Evil.COM")).toEqual(["evil.com"]); }); + + test("drops the trailing dot of a fully qualified hostname", () => { + expect(hostnameVariants("sub.evil.com.")).toEqual([ + "sub.evil.com", + "evil.com", + ]); + }); }); describe("domain hashing", () => {