The actionSendActivationEmail() endpoint is accessible to unauthenticated users and does not require a permission check for pending users. An attacker with no prior access can trigger activation emails for any pending user account by knowing or guessing the user ID. If the attacker controls the target user’s email address, they can activate the account and gain access to the system.
The vulnerability is not that anonymous access exists - there’s a legitimate use case for it. The vulnerability is that the endpoint accepts arbitrary userId parameters without verifying ownership.
Craft CMS allows public user registration. When a user registers but doesn’t receive their activation email (spam filter, typo correction, etc.), they need a way to request a resend. This is why send-activation-email is in the allowAnonymous array - it’s intentional self-service functionality.
The endpoint accepts userId as the identifier:
$userId = $this->request->getRequiredBodyParam('userId');
This allows any visitor to trigger activation emails for any pending user, not just their own registration.
When administrators create new user accounts in Craft CMS, users are created in a “pending” state until they activate their account via an emailed link. The actionSendActivationEmail() function sends (or resends) this activation email.
Expected Behavior: Anonymous users should only be able to resend activation emails for their own registration.
Actual Behavior:
allowAnonymous - no login required (intentional for self-service)Prerequisites: Attacker controls target user’s email (compromised email, shared mailbox, typosquatting, etc.)
1. Admin creates a user account...
4.17.0-beta.25.9.0-beta.2Exploitability
AV:NAC:LAT:NPR:NUI:NVulnerable System
VC:LVI:HVA:NSubsequent System
SC:NSI:NSA:N7.8/CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N/E:P