WP Manifestindependent plugin directory

2FA WP Registry grade D+. High-severity findings · 4 findingsWP RegistryHigh-severity findings · 4 findingsOpen the reportD+

WordPress plugin for 2 factor authentication (TOTP and SMS)

★ 6stars
19composer installs
v2.0.4latest · 5mo ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/dxw/2fa/archive/refs/heads/main.zip

On Packagist as dxw/2fa:

composer require dxw/2fa
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

WordPress plugin for 2 factor authentication (TOTP and SMS)

Installation

At the moment this plugin must be installed on a multisite installation.

To enable SMS authentication add these constants to your wp-config.php:

define('TWILIO_ACCOUNT_SID', 'AC...');
define('TWILIO_AUTH_TOKEN', '...');
define('TWILIO_NUMBER', '...');

You can find those here.

To disable 2FA options from being selectable, add constants as follows:

  • 2FA_SMS_DISABLED to disable SMS (for example if no Twilio account is setup)
  • 2FA_SMART_DEVICE_DISABLED to disable smartphone or tablet option

Usage

Super admins can decide which users must use 2FA. Users cannot opt to start using 2FA if it has not been enabled for their account.

Super admins can do this in two ways - setting an option on the user's profile to "enabled", or by checking the checkbox in the list of sites which forces all users of a site to use 2FA.

Users will then be forced to setup 2FA the next time they log in (it will not interrupt a user who is already logged in).

They have the option of using TOTP (apps like Google Authenticator) or SMS. And they can configure up to 2 devices (controlled by a constant).

Admins can also set the number of days users can skip requests for their second factor when logging in.

wp-cli command

% wp 2fa fails
% wp 2fa user alice
% wp 2fa reset bob

Tests

Unit tests and linter:

% composer install
% vendor/bin/peridot spec
% vendor/bin/php-cs-fixer fix --dry-run -v --diff

Integration tests:

% tests/run-with-docker.sh

Licence

MIT

Releases

7 releases.

Tag
Published
v2.0.4 latest
May 11, 2026 5mo ago
Nov 15, 2024 1 year ago
May 30, 2024 2 years ago
May 16, 2024 2 years ago
Mar 18, 2024 2 years ago
Feb 7, 2024 2 years ago
Nov 14, 2023 2 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

D+ grade

Security

2FA 2.0.4 · audited by WP Registry

High-severity findings.

2 high 2 medium
Audited release
2.0.4
Findings
4
Worst severity
high
Content hash
ff0743dbe5cac65d97b8503f…

Findings

  • high 2FA not applied to XML-RPC, application passwords, or other authenticate paths

    auth_bypass

    The plugin replaces only the wp-login.php login form via login_form_login. It never hooks authenticate, wp_authenticate_user, xmlrpc_enabled, or application-password authentication. A user who is 2FA-enabled and has devices configured must enter a TOTP/SMS/email code on wp-login.php, but the same username and password authenticate successfully on xmlrpc.php (wp.getUsersBlogs, metaWeblog, wp.uploadFile, system.multicall), via WordPress application passwords on the REST API, and via any plugin that calls wp_signon()/wp_set_auth_cookie() (custom/WooCommerce login forms). For an administrator this is a full second-factor bypass and account takeover using only the stolen password. Fix by denying XML-RPC for 2FA-enabled users (or prompting for a token there) and by hooking authenticate so application passwords are the only documented API exception, if any.

    lib/login.php:154-245

    Recommendation

    Hook the authenticate filter (and/or xmlrpc_login_error / application_password_is_api_request) so a 2FA-enabled user with devices cannot obtain a session or XML-RPC/REST identity with password alone. Disable or challenge XML-RPC for those users. Do not rely solely on login_form_login.

  • high Password-only login during 2FA setup issues a full session; jail exempts AJAX and REST

    auth_bypass

    If 2FA is mandated but the user has not registered a device, twofa_user_activated() is 0, so login_form_login calls twofa_wp_set_auth_cookie immediately (password only). The intended control is force-setup on admin_init, which redirects to users.php?page=2fa&step=setup. That redirect is skipped when DOING_AJAX is true, and admin_init does not run on REST API or front-end requests. A stolen password for an administrator who has not finished enrollment (the default window after a super admin enables 2FA for a site, and after wp_ajax_2fa_deactivate wipes 2fa_devices) therefore yields a working auth cookie. The attacker can POST /wp-json/wp/v2/users, /wp-json/wp/v2/plugins, and core admin-ajax actions such as install-plugin or add-user without visiting the setup screen. The plugin's own conceptual model says an incomplete user 'must configure a device to proceed'; the $ajax short-circuit is broader than the plugin's own setup actions.

    lib/force-setup.php:16-36

    Recommendation

    Do not call wp_set_auth_cookie until a device is registered, or mark the session as 2FA-pending and reject REST/admin-ajax/front-end cookie auth until setup completes. If AJAX must work for setup, allow-list only this plugin's 2fa_* actions instead of all DOING_AJAX.

  • medium Site admins can wipe any network user's 2FA devices without edit_user

    missing_capability

    wp_ajax_2fa_deactivate verifies nonce 2fa_deactivate and current_user_can('remove_users'), then sets 2fa_devices to null for an arbitrary POST user id. There is no current_user_can('edit_user', $user_id), no manage_sites check (the same plugin requires manage_sites to change 2fa_override), and no check that the target belongs to the current site. On multisite, a site administrator has remove_users but cannot edit super admins via profile.php. This handler still lets them strip the super admin's TOTP/SMS/email devices. Combined with password-only login when device count is zero, that removes the second factor until the victim re-enrolls. Subscriber/editor cannot call it; Administrator/site admin can.

    lib/users-list.php:37-59

    Recommendation

    Require current_user_can('edit_user', $user_id) (and manage_sites or manage_network_users for super-admin targets). Restrict the target to users the caller is allowed to list. Consider manage_sites for network-wide 2FA resets, matching 2fa_override.

  • medium Unauthenticated-rate SMS to arbitrary numbers via setup AJAX

    unsafe_input

    wp_ajax_2fa_sms_send_verification accepts any POST number after a nonce check, stores it as 2fa_sms_temporary_number, and calls twofa_sms_send_token → Twilio messages->create with no E.164 validation, no twofa_user_enabled() gate, and no per-user or per-IP rate limit. The setup UI (capability read) prints the nonce for every 2FA-mandated user, including subscribers on a site with 2fa_enabled. An attacker can loop admin-ajax.php?action=2fa_sms_send_verification to pump SMS to premium-rate numbers (Twilio toll fraud) or to flood a victim number. Requires TWILIO_* constants; if SMS is disabled in config the handler still exists and will error only after the request is processed. The same handler does not confirm the number belongs to the current user.

    lib/setup.php:86-111

    Recommendation

    Validate E.164, require twofa_user_enabled() and remaining device slots, and rate-limit sends per user and per number. Consider confirming the number out-of-band before calling Twilio. Reject requests when TWILIO_* is unset before writing meta.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.