Summary
The Email Gatekeeper lets any authenticated user permanently reserve any valid mailbox local part. A user who claims a name first prevents the intended owner from claiming it later, and disconnecting does not release the name. On a deployment where all users can use the Email Gatekeeper, this creates a mailbox-name reservation/denial-of-service risk.
Evidence
packages/gatekeeper-email/src/email.ts accepts a canonical /mailbox/<name> URL in GatekeeperUserImpl.getGatekeeperClassFor() (around lines 386-438), then calls EmailAddress.claim(userAccountId) before recording the association in the caller's UserAccount.
EmailAddress.claim() (around lines 614-627) stores the first caller as owner and rejects every different caller. Its comments describe that owner as permanent. GatekeeperUserImpl.revoke() (around lines 441-449) deliberately disconnects hooks without releasing address claims, so the reservation survives disconnecting.
Reproduction from the current source
- Authenticate two different Workshop users on the same deployment.
- Have user A create an Email Mailbox binding for
target-name.
- Have user B create a binding for the same canonical URL.
- User B receives
This email address is claimed by another user.
- Repeat with other valid names. User A can reserve names without proving control of the corresponding email address.
This is based on the current source path and ownership comments; I have not run this against a deployed SMTP/Email Routing setup.
Impact and design question
This is not an auth bypass: it prevents another user from claiming a name rather than granting the attacker access to the victim's mailbox. It is a namespace reservation problem that can block legitimate mailbox setup and may be exploitable by iterating names.
Please decide which policy is intended:
- only deployment admins may reserve mailbox names;
- claims should be released when an account disconnects, with safeguards for active routing; or
- users must prove control of an address before claiming it.
I am not proposing a PR because the correct fix changes mailbox ownership semantics, and CONTRIBUTING.md asks external contributors to report bugs rather than submit design-level patches.
Summary
The Email Gatekeeper lets any authenticated user permanently reserve any valid mailbox local part. A user who claims a name first prevents the intended owner from claiming it later, and disconnecting does not release the name. On a deployment where all users can use the Email Gatekeeper, this creates a mailbox-name reservation/denial-of-service risk.
Evidence
packages/gatekeeper-email/src/email.tsaccepts a canonical/mailbox/<name>URL inGatekeeperUserImpl.getGatekeeperClassFor()(around lines 386-438), then callsEmailAddress.claim(userAccountId)before recording the association in the caller'sUserAccount.EmailAddress.claim()(around lines 614-627) stores the first caller asownerand rejects every different caller. Its comments describe that owner as permanent.GatekeeperUserImpl.revoke()(around lines 441-449) deliberately disconnects hooks without releasing address claims, so the reservation survives disconnecting.Reproduction from the current source
target-name.This email address is claimed by another user.This is based on the current source path and ownership comments; I have not run this against a deployed SMTP/Email Routing setup.
Impact and design question
This is not an auth bypass: it prevents another user from claiming a name rather than granting the attacker access to the victim's mailbox. It is a namespace reservation problem that can block legitimate mailbox setup and may be exploitable by iterating names.
Please decide which policy is intended:
I am not proposing a PR because the correct fix changes mailbox ownership semantics, and
CONTRIBUTING.mdasks external contributors to report bugs rather than submit design-level patches.