Hi,
Filing on behalf of an enterprise customer where Zoho Vault is deployed across the company. The Chrome extension blocks WebAuthn passkey registration on legitimate sites whose Relying Party ID (rpId) has a TLD longer than 6 letters. This affects every post-2012 ICANN gTLD: .accountant, .technology, .consulting, .engineering, .management, .business, .finance, .lawyer, .museum, .travel, etc.
Reproduction
DOMException("Passkey request is blocked due to an insecure or mismatched website address. Please check your website address and try logging in again.", "SecurityError")Pausing the extension on the same site, or replacing navigator.credentials.create with the unwrapped CredentialsContainer.prototype.create from the page console, lets registration succeed via Windows Hello. So the underlying WebAuthn call is fine; the extension is the gatekeeper.
Root cause (visible in your content script)
Your wrapper around navigator.credentials.create calls PasskeyHelper.isValidRpId(rp.id), which calls PasskeyHelper.isValidDomain(rpId). The latter is:
static isValidDomain = (str) => {
let regexp = /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/i;
return regexp.test(str);
};The {2,6} cap on the final label rejects every TLD with 7+ letters. For example, "secure.app.boosted.accountant" passes the W3C WebAuthn rules but fails this regex, so isValidDomain returns false, isValidRpId returns false, and createPasskey throws SecurityError.
In createPasskey itself:
if (!PasskeyHelper.isValidRpId(options.publicKey.rp.id)) {
throw new DOMException(errorTexts[VI18N.PASSKEY_SECURITY_ERROR],
PasskeyError.SecurityError);
}There is no fallback to the native API on this branch. Other failure paths in the same function (not signed in, passkey unavailable, NotAllowedError from the background script) correctly fall through to originalCredentials.create.apply(this, arguments) so the OS provider (Windows Hello, security key) can handle the call. The isValidRpId branch does not.
Per W3C WebAuthn L2 §5.1.3, an rpId is valid when it equals, or is a registrable suffix of, the calling document's effective domain. There is no spec restriction on TLD length.
Asks
PasskeyHelper.isValidDomain. The minimal fix is to drop the upper bound, e.g. /^[a-z0-9]+([\-\.][a-z0-9]+)*\.[a-z]{2,}$/i. Better: align with the WebAuthn L2 algorithm (origin equality OR registrable-suffix via the Public Suffix List).originalCredentials.create.apply(this, arguments) instead of throwing. You already do this for the other fallback paths. Throwing makes the user unable to use any passkey provider at all — Vault has effectively hijacked WebAuthn for that origin and refused, with no escape hatch short of pausing the extension. A one-line change.Impact
Enterprise customers who standardise on Zoho Vault cannot register passkeys on any site whose rpId uses a non-legacy TLD. Workaround today is "pause Vault for the site," which doesn't scale to a full organisation.
Sanity check anyone can run in a browser console:
/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/i.test("secure.app.boosted.accountant") // false
/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/i.test("example.com") // trueHappy to provide more details, screenshots, or do a screenshare. Thanks.