Sudo will prevent or radically reduce the damage attackers can do if they hijack an authenticated session or penetrate firewalls and exploit a Broken Access Control (BAC), Broken Authentication, Privilege Escalation, or Cross-Site Request Forgery (CSRF) vulnerability. It also defends against scenarios where a device is stolen or left unattended, or any scenario allowing an attacker to take control of an active user session. These types of threats are becoming increasingly common and a leading source of breaches across all platforms.
Broken Access Control is the #1 web application vulnerability today. OWASP ranked it #1 in its 2025 Top 10 list after finding this type of vulnerability in 100% of its application test samples (OWASP 2025). In the WordPress ecosystem, Broken Access Control was the second-largest category of new vulnerabilities in 2024, after XSS (Patchstack 2024). In 2025, Broken Access Control vulnerabilities became the target of 57% of all attacks on WordPress sites (Patchstack 2025). This surge is most likely the result of threat actors shifting away from XSS and concentrating their efforts on the types of attacks that firewalls are least likely to identify or predict, even with machine learning. As Patchstack notes:
[Broken Access Control] vulnerabilities are very difficult to defend against using traditional WAFs because the exploits look like normal authenticated traffic with no obvious injection patterns.
Add CSRF, Privilege Escalation, and Broken Authentication β all access control failures β and you're looking at 28% of all WordPress vulnerabilities catalogued in 2024. (Patchstack, State of WordPress Security in 2026)
Verizon's 2025 Data Breach Investigations Report finds that 77β88% of basic web application attacks begin with stolen credentials. Sucuri's forensics show that 55% of hacked WordPress databases contain malicious admin accounts created after the breach. The attacker doesn't need to find a new exploit β they need an active session, and they need WordPress to do what attackers assume it will always do: obey without challenge.
Sudo breaks that assumption β a key link in the attackers' kill chain. With Sudo active, every destructive action β user creation, plugin installation, role change, settings modification β requires password confirmation at the moment of execution. A stolen session cookie is not enough. An unattended browser is not enough. If a broken access control is the attack vector, Sudo is the guarded gate that will not allow it to pass.
Sudo will neutralize attacks or severely limit their blast radius (the scope of the harm they can do) if the attacks rely on taking privileged actions or aim to achieve that capability as their goal.
Sudo is not intended as a replacement for diligent plugin selection, timely updates, and effective firewalling; instead, it complements and backstops those layers of defense.
When the firewall misses an exploit, the vulnerable plugin it targets hasn't been patched, and/or the attacker already has an active session, Sudo is the gate between access and damage. Plugin installs, user creation, role changes, settings modifications: every destructive action requires reauthentication, regardless of how the attacker got in.
No security plugin gates actions that authenticated users can take. Most WordPress security plugins entirely neglect internal user-level security and do not make it a matter of governable policy.
Why this matters: Any authenticated user session is an attack surface. Attackers can acquire an authenticated user session in many ways:
- A broken access control vulnerability that can be exploited to create a rogue user account.
- A stolen session cookie lets an attacker take over your session from another browser without knowing your password.
- An unattended machine with an active admin session leaves gated operations open to anyone with physical access.
- Open APIs allow authenticated and unauthenticated remote users and automated systems to probe them, connect, and potentially take damaging actions.
Conventional security plugins attempt to compensate for the limitations of mass-market hosting and plugins. Often, a security plugin will add layers of protection at the application level β rate-limiting and firewalling aimed at deterring malicious requests across some (typically under-defined) portion of the exposed application surface. This can be resource-intensive work that is better handled at the server, network, or infrastructure layer. Rapid mitigation through virtual patching based on the latest threat intelligence about vulnerable code is extremely valuable. If that layer is missing or fails, Sudo is the final layer of protection. Post-breach malware scanning β the signature and purely performative feature of the worst security plugins β is not a security layer. It is detection after the fact β not defense. Years of mounting evidence show how malware targets and defeats these scanners after a breach.
Sudo doesn't operate at the perimeter but at the final point of consequence. It gates every entry surface β admin UI, AJAX, REST API, WP-CLI, Cron, XML-RPC, and WPGraphQL β with configurable policies, and within those surfaces gates the specific destructive actions that matter: plugin installation, user creation, role changes, settings modifications, theme switching, and core updates. The shape and extent of your site's attack surface becomes a deliberate policy decision. Close a surface entirely, limit it to non-destructive operations, or leave it open β per surface, per application password, per action.
This is your site's innermost armor β the skin-tight layer that interposes reauthentication at the moment of consequence, after every other defense has had its turn. There is no comparable WordPress plugin. This is not access control β it is action control. For a detailed feature-by-feature comparison with other reauthentication approaches, see the Architecture Comparison Matrix.
Why this matters by the numbers. Of the 7,966 WordPress vulnerabilities catalogued in 2024 (Patchstack), ~28% fall into classes Sudo directly mitigates (Broken Access Control, CSRF, Privilege Escalation, Broken Authentication). When XSS exploitation chains are included, the figure rises to 55β65%. (XSS currently accounts for 47.7% of all WordPress vulnerabilities and is primarily dangerous because it enables session hijacking β admin actions.) Post-compromise, Sucuri found that 55% of hacked WordPress databases contained malicious admin users and 49β70% had backdoor plugins β both actions that Sudo gates. In 2025, the total rose 42% to 11,334 (Patchstack), with highly exploitable vulnerabilities up 113% and traditional WAFs blocking only 12β26% of WordPress-specific attacks. When measured by actual exploitation attempts rather than discovery counts, Sudo-mitigated vulnerability classes account for 80% of real-world WordPress attacks (Patchstack 2025 RapidMitigate data) β Broken Access Control alone represents 57%. See the Security Model for the full threat model and risk reduction estimates.
Sudo is complementary to any other security layers you put in place. It doesn't compete with your WAF, for instance β it's the defense that matters when the WAF fails. Plugins that help you authenticate and manage users or software updates, or identify vulnerabilities in code and user accounts, are completely complementary. Two-factor authentication is critically important, and Sudo is specifically designed to work with the WordPress community standard solution for 2FA.
WP Sudo does not protect against an attacker who already knows your WordPress password and one-time password (OTP) if two-factor authentication (2FA) is active. (Using two-factor is highly recommended on any site.) Someone who possesses all your credentials can, of course, complete the sudo challenge just as you can. Sudo also does not protect against direct database access or file system operations that bypass WordPress hooks. See the Security Model for a full account of what WP Sudo does and does not defend against.
Also, there is no substitute for a first-class, security-hardened server and application environment. Learn what this means so you can deploy secure sites yourself or simply become a savvier hosting consumer:
- WordPress Security Hardening Guide (Accessible to relatively non-technical readers.)
- WordPress Security Benchmark (Patterned after CIS Benchmarks β a pragmatic technical reference for key security decisions and tradeoffs when you stand up a WordPress server.)
When a user attempts a gated action β for example, activating a plugin β Sudo intercepts the request at admin_init, before WordPress processes it. The original request is stashed in a transient, the user is redirected to a challenge page, and after successful reauthentication, the original request is replayed. For AJAX and REST requests, the browser receives a sudo_required error, and an admin notice appears on the next page load linking to the challenge page. The user authenticates, activates a sudo session, and retries the action.
No. Sudo adds a reauthentication layer on top of the existing permission model. WordPress capability checks still run after the gate. A user who does not have the activate_plugins capability will still be denied after reauthenticating β Sudo does not grant any new permissions.
| Category | Operations |
|---|---|
| Plugins | Activate, deactivate, delete, install, update |
| Themes | Switch, delete, install, update |
| Users | Delete, change role, change password, create new user, create application password |
| File editors | Plugin editor, theme editor |
| Critical options | siteurl, home, admin_email, default_role, users_can_register |
| WordPress core | Update, reinstall |
| Site data export | WXR export |
| WP Sudo settings | Self-protected β settings changes require reauthentication |
| Multisite | Network theme enable/disable, site delete/deactivate/archive/spam, super admin grant/revoke, network settings |
Sudo's settings page includes a read-only Gated Actions table showing all registered rules and their covered surfaces: Admin, AJAX, WP-CLI, Cron, REST, XML-RPC, and GraphQL, if it's installed and active.
Note: the surfaces shown reflect WordPress's actual API coverage β not all operations have REST endpoints. However, all gated actions are protected on non-interactive entry points (WP-CLI, Cron, XML-RPC, Application Passwords) via the configurable policy settings. Developers can add custom rules via the wp_sudo_gated_actions filter.
Cookie-authenticated REST requests (from the block editor, admin AJAX) receive a sudo_required error. An admin notice on the next page load links to the challenge page where the user can authenticate and activate a sudo session, then retry the action. Application Password and bearer-token REST requests are governed by a separate policy setting with three modes: Disabled (returns sudo_disabled), Limited (default β returns sudo_blocked), and Unrestricted (passes through with no checks). Individual application passwords can override the global policy from the user profile page β for example, a deployment pipeline password can be Unrestricted while an AI assistant password stays Limited. For guidance on configuring WP Sudo for AI agents and automated tools, see AI & Agentic Tool Integration.
Each has its own three-tier policy setting: Disabled, Limited (default), or Unrestricted. In Limited mode, gated actions are blocked and logged via audit hooks while non-gated commands work normally. When CLI is Limited or Unrestricted, wp cron subcommands still respect the Cron policy β if Cron is Disabled, those commands are blocked even when CLI allows other operations.
When the WPGraphQL plugin is active, WP Sudo adds its own WPGraphQL policy setting with the same three modes: Disabled, Limited (default), and Unrestricted. WPGraphQL gating works at the surface level rather than per-action: in Limited mode, all mutations require an active sudo session while read-only queries always pass through. In Disabled mode, all requests to the endpoint are rejected. WP Sudo detects mutations by inspecting the request body for a mutation operation type. WPGraphQL handles its own URL routing, so gating works regardless of how the endpoint is configured.
WP Sudo's action registry rules are tied to WordPress action hooks β activate_plugin, delete_user, wp_update_options, and so on. These hooks fire regardless of entry surface, which is how the same rules cover the admin UI, AJAX, and REST simultaneously.
WPGraphQL mutations do not reliably fire those same hooks. WPGraphQL dispatches through its own resolver chain, and whether a mutation eventually triggers a WordPress hook depends entirely on how each resolver is implemented. There is no guaranteed 1:1 mapping from "mutation name" to "WordPress action hook" across the full WPGraphQL ecosystem (core resolvers, WooCommerce, custom extensions).
Per-action gating would require either parsing GraphQL request bodies to extract operation names and maintaining a mutationβhook mapping, or a new WPGraphQL-specific rule type separate from the hook-based registry. Both carry significant ongoing maintenance costs for the plugins and custom mutations that WPGraphQL-based sites rely on.
The surface-level approach β blocking any request body containing mutation in Limited mode β is reliable and appropriate for the primary use case: headless deployments where mutations come from automated API clients rather than interactive admin users. For mutations that should not require a sudo session (content mutations, authentication handshakes, etc.), the wp_sudo_wpgraphql_bypass filter provides precise per-mutation control without modifying the global policy.
FYI: In GraphQL, a "mutation" is a type of operation used to modify server-side data, causing side effects on the back end. While queries are used for fetching data, mutations are specifically designed for creating, updating, or deleting data. (This is similar to POST, PUT, PATCH, or DELETE in REST.)
The wp-graphql-jwt-authentication plugin is the standard way to authenticate WPGraphQL requests using JSON Web Tokens. With WP Sudo's default Limited policy, two issues arise: (1) the JWT login mutation is sent by unauthenticated users who cannot have a sudo session, so it is blocked; (2) JWT-authenticated mutations fail because JWT requests do not carry the browser-bound sudo session cookie. The result is that Limited mode breaks the JWT authentication flow entirely.
Solution: Use the wp_sudo_wpgraphql_bypass filter (added in v2.7.0) to exempt authentication mutations. Add this to a mu-plugin:
add_filter( 'wp_sudo_wpgraphql_bypass', function ( bool $bypass, string $body ): bool {
if ( $bypass ) {
return $bypass;
}
if ( str_contains( $body, 'login' ) || str_contains( $body, 'refreshJwtAuthToken' ) ) {
return true;
}
return false;
}, 10, 2 );This exempts only the login and refreshJwtAuthToken mutations β all other mutations remain gated. Alternatively, set the policy to Unrestricted if you do not need mutation-level gating. See the developer reference for full details.
The Abilities API (introduced in WordPress 6.9) registers its own REST namespace at /wp-abilities/v1/. It uses standard WordPress REST authentication, so Application Passwordβauthenticated requests are governed by WP Sudo's REST API (App Passwords) policy β no special configuration is needed. In Disabled mode, all Abilities API requests via Application Passwords are blocked. In Limited mode, ability reads, and standard executions pass through as non-gated operations; site owners who want to require sudo for specific destructive ability executions can add custom rules via the wp_sudo_gated_actions filter.
When sudo is activated, a cryptographic token is stored in a secure httponly cookie, and its hash is saved in user meta. On every gated request, both must match. A stolen session cookie on a different browser will not have a valid sudo session. See Security Model for full details.
When the password step succeeds, and 2FA is required, a one-time challenge cookie is set in the browser. The 2FA pending state is keyed by the hash of this cookie, not by user ID. An attacker who stole the WordPress session cookie but is on a different machine does not have the challenge cookie and cannot complete the 2FA step. See Security Model for full details.
Yes. After 5 failed password attempts on the reauthentication form, the user is locked out for 5 minutes. Lockout events fire the wp_sudo_lockout action hook for audit logging.
Install WP Activity Log or Stream. Sudo fires 9 action hooks covering session lifecycle, gated actions, policy decisions, lockouts, and tamper detection. See Developer Reference for hook signatures.
Yes. If the Two Factor plugin is installed and the user has 2FA enabled, the sudo challenge becomes a two-step process: password first, then the configured 2FA method (TOTP, email code, backup codes, etc.). For passkey and security key support, add the WebAuthn Provider for Two Factor plugin. A visible countdown timer shows how long the user has to enter their code. Third-party 2FA plugins can integrate via filter hooks β see Developer Reference.
Yes. Settings are network-wide (one configuration for all sites). Sudo sessions use user meta (shared across the network), so authenticating on one site covers all sites. The action registry includes network-specific rules for theme enable/disable, site management, super admin grant/revoke, and network settings. The settings page appears under Network Admin > Settings > Sudo. On uninstall, per-site data is cleaned per-site, and user meta is only removed when no remaining site has the plugin active.
On multisite, WordPress core already removes the most dangerous General Settings fields (site URL, home URL, membership, default role) from subsite admin pages β only Super Admins can change those at the network level. The remaining subsite settings (site title, tagline, admin email, timezone, date/time formats) are low-risk and not gated. Changing the admin email also requires email confirmation by WordPress core. Network-level operations β network settings, theme management, site creation/deletion, and Super Admin grants β are all gated.
The "must-use" mu-plugin is optional but highly recommended. It ensures Sudo's gate hooks are registered before any other regular plugin loads, preventing another plugin from deregistering the hooks or processing dangerous actions before the gate fires. You can install it with one click from the settings page or follow the instructions for copying it to the /mu-plugins folder. (You may need to do this manually in many hosting environments.) The mu-plugin is a thin shim in wp-content/mu-plugins/ that loads the gate code from the main plugin directory β it updates automatically with regular plugin updates.
Any active sudo sessions expire naturally. All gated actions return to their normal, ungated behavior. No data is lost. The MU-plugin shim (if installed) checks the active_plugins option on each request and remains inert when the main plugin is deactivated β no gate hooks are registered, and no plugin code is loaded. On uninstall, the shim file is automatically deleted from wp-content/mu-plugins/.
Yes. Use the wp_sudo_gated_actions filter to add custom rules. See Developer Reference for the rule structure and code examples.
Yes. The default window is 5 minutes. Use the wp_sudo_two_factor_window filter to adjust it (value in seconds). You cannot make it lower than 1 minute or higher than 15 minutes. A tiny window maximizes user inconvenience, and a large window minimizes the security benefits. 10-15 minutes is the industry norm, with 10m the usual default in *nix systems. See Developer Reference.
Yes (since v2.6.0). A successful browser-based WordPress login implicitly activates a sudo session. The user just proved their identity via the login form β requiring a second challenge immediately is unnecessary friction. This mirrors the behaviour of Unix sudo and GitHub's sudo mode.
Application Password and XML-RPC logins are not affected β the wp_login hook only fires for browser form logins, and these non-interactive paths don't produce a session cookie anyway.
Password changes on profile.php, user-edit.php, or via the REST API (PUT/PATCH /wp/v2/users/{id}) are themselves a gated action (since v2.6.0), so they already require an active sudo session to proceed. Since v2.8.0, WP Sudo automatically expires the sudo session when a password change is saved.
A 2-minute wind-down window (since v2.6.0) allows gated actions to pass for 120 seconds after session expiry, provided the session token is still valid. This prevents form submissions and multi-step workflows from being interrupted by session expiry β without it, a user who spent three minutes on a form would have their work rejected and need to reauthenticate, losing any unsaved input.
How it works: When the gate checks the session, it first calls Sudo_Session::is_active(). If the session has expired, it also calls is_within_grace(). If the expiry happened within the last 120 seconds and the session token still matches (session binding is enforced throughout), the request passes. The gate does not distinguish between actions that were "in progress" before expiry and new ones β any gated action within the window is permitted if the token is valid.
What it does not relax: session binding. A stolen cookie on a different browser does not gain grace-period access. The session token must still match β is_within_grace() calls verify_token() before returning true. The admin bar timer always reflects the true session state (is_active()), not the grace state β the user sees accurately when their session has expired.