Repository navigation
1.10.0
Fix 2FA bypass vulnerabilities
What was broken
edit_user/edit_userswere allow-listed for 2FA-less accounts, letting them edit any user's profile.admin-ajax.phpwas fully open pre-2FA instead of scoped to what's actually needed.- 2FA requirement is determined by email domain (
@829llc.com= SSO, exempt) — a 2FA-less admin could change their own email to instantly escape the requirement. - 2FA activated immediately on save with no ownership verification — a stolen password on an account without 2fa could still gain access.
What changed
- Capability lockdown:
edit_user/edit_usersremoved from the allow-list; self-profile edits now strictly scoped to the user's own ID. - Ajax lockdown:
admin-ajax.phpaccess for 2FA-less accounts limited to only the actionsprofile.phpneeds. - Email lock: 2FA-less users can no longer change their own email, enforced at the data layer so it holds across wp-admin, REST, ajax, and CLI.
- Email-confirmed activation: enabling 2FA now sends a confirmation link that must be clicked (via POST, resistant to link-prefetching scanners) before it actually activates, so a user cannot set up 2fa unless they have access to the account email address. A notice shows while confirmation is pending.
Testing
- Verified the REST bypass (
POST /wp/v2/users/meemail change) is blocked. - Verified capability/ajax restrictions don't break the legitimate profile/2FA-setup flow.
- Reviewed for new vulnerabilities in this diff (token binding, confirmation-link security) — fixed a token-binding weakness and hardened the confirmation link against link-prefetching scanners.
No impact on existing accounts
- SSO (
@829llc.com) accounts and non-SSO accounts that already have 2FA enabled are unaffected by any of these changes.
Add 2FA login exceptions for third-party integration accounts
Service accounts that hit the REST API with an application password can't complete a 2FA challenge, so TwoFactor permanently strips them down to read. Needed for the Tourcube integration.
Adds an External Email Users → 2FA Login Exceptions field to the 829 Settings page (same user-search pattern as Credential Login Exceptions), and exempts those users in user_requires_2fa().
Note this removes our enforcement only — the Two-Factor plugin will still challenge an exempted user who already has 2FA set up.