You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
docs: align docs with shipped 4.1.0 code and prep release (#113)
Pre-release documentation sweep aligning all docs with the shipped 4.1.0 code
(escalation guard #111, REST backstop #104), with code as the source of truth:
escalation guard documented (filters/action/constant) with its default-OFF
posture and blind spots stated in FAQ + security-model; corrected now-false
boundary claims (multisite cap-key regex; role/user-create coverage); analysis
doc + gate-completeness report marked implemented/closed; Gate architecture
description updated in CLAUDE.md/AGENTS.md; CHANGELOG dated and release-status
refreshed for the 4.1.0 line; blind spots logged as tracked future mitigation;
drift findings + external-claims audit recorded in llm-lies-log. Docs-only.
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -232,7 +232,7 @@ behavior that the model cannot hold in working memory.
232
232
### Core Classes (all in `includes/`, namespace `WP_Sudo`)
233
233
234
234
-**Plugin** — Orchestrator. Creates and owns the component instances. Handles activation/deactivation hooks. Strips `unfiltered_html` from editors on activation and restores it on deactivation. Expires sudo session on password change (`after_password_reset`, `profile_update`).
235
-
-**Gate** — Multi-surface interceptor. Matches incoming requests against the Action Registry and gates them via reauthentication (admin UI), error response (AJAX/REST), or policy (CLI/Cron/XML-RPC/App Passwords).
235
+
-**Gate** — Multi-surface interceptor. Matches incoming requests against the Action Registry and gates them via reauthentication (admin UI), error response (AJAX/REST), or policy (CLI/Cron/XML-RPC/App Passwords). Beyond request-pattern matching it also arms **effect-level backstops** — interactive (`admin_init`) and REST (`register_rest_backstop`) — that hard-block unambiguous destructive effects reached through non-enumerated handlers (4.1.0), plus an opt-in, **default-OFF admin-escalation guard** (`arm_escalation_guard`, filter `wp_sudo_guard_escalation`) that blocks a newly-granted administrator/super-admin without an active sudo session by hooking the `{prefix}capabilities` meta write and `grant_super_admin`.
236
236
-**Action_Registry** — Defines all built-in gated rules and rule categories. Extensible via `wp_sudo_gated_actions` filter. See `docs/current-metrics.md` for the current single-site/multisite totals.
-`docs/release-status.md` — canonical current release status: stable tag, unreleased `main` work, and WordPress forward-lane posture.
128
128
-`docs/wporg-submission-checklist.md` — WordPress.org submission process: validation gates, asset specs, SVN trunk/tags layout, and the version-sync gate.
129
-
-`docs/documentation-remediation-checklist.md` — audit-driven cleanup checklist for doc drift and archival labeling.
130
129
131
130
## Verification Requirements
132
131
@@ -273,7 +272,7 @@ Specifically, do **not** write:
273
272
### Core Classes (all in `includes/`, namespace `WP_Sudo`)
274
273
275
274
-**Plugin** — Orchestrator. Creates and owns the component instances. Handles activation/deactivation hooks. Strips `unfiltered_html` from editors on activation and restores it on deactivation. Expires sudo session on password change (`after_password_reset`, `profile_update`).
276
-
-**Gate** — Multi-surface interceptor. Matches incoming requests against the Action Registry and gates them via reauthentication (admin UI), error response (AJAX/REST), or policy (CLI/Cron/XML-RPC/App Passwords).
275
+
-**Gate** — Multi-surface interceptor. Matches incoming requests against the Action Registry and gates them via reauthentication (admin UI), error response (AJAX/REST), or policy (CLI/Cron/XML-RPC/App Passwords). Beyond request-pattern matching it also arms **effect-level backstops** — interactive (`admin_init`) and REST (`register_rest_backstop`) — that hard-block unambiguous destructive effects reached through non-enumerated handlers (4.1.0), plus an opt-in, **default-OFF admin-escalation guard** (`arm_escalation_guard`, filter `wp_sudo_guard_escalation`) that blocks a newly-granted administrator/super-admin without an active sudo session by hooking the `{prefix}capabilities` meta write and `grant_super_admin`.
277
276
-**Action_Registry** — Defines all built-in gated rules and rule categories. Extensible via `wp_sudo_gated_actions` filter. See `docs/current-metrics.md` for the current single-site/multisite totals.
Copy file name to clipboardExpand all lines: docs/FAQ.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,7 +32,9 @@ It depends entirely on where the exploit path goes.
32
32
33
33
**Yes, if the attack crosses a covered surface.** An attacker who exploits a plugin vulnerability to gain a session and then tries to perform a covered high-risk operation — activate a plugin, create an admin user, change a role — through the standard admin UI, AJAX, or REST path that WP Sudo intercepts will hit the gate. The attacker has no sudo session, so the operation is blocked regardless of how they obtained their session. This is the core kill-chain interception: even with a valid session, covered destructive actions require credential proof.
34
34
35
-
**No, if the exploit runs through the plugin's own path.** If the vulnerable plugin calls `wp_set_role()`, `wp_insert_user()`, or similar WordPress functions from inside its own AJAX handler or REST endpoint — without routing through a standard surface WP Sudo has been positioned to intercept — the gate never fires. WP Sudo cannot invent interception points for code it does not see.
35
+
**Yes, even through the plugin's own path — if you enable the admin-escalation guard (4.1.0, opt-in, default OFF).** Turning on the `wp_sudo_guard_escalation` filter makes WP Sudo hook the *effect* of an administrator grant (the `{prefix}capabilities` user-meta write and `grant_super_admin`) rather than a surface, so it blocks a **newly granted** `administrator` (single-site) or super-admin (multisite) on *any* path — a plugin's own AJAX/REST handler, or even an unauthenticated request — whenever the actor has no active sudo session. Because an unauthenticated or low-privilege attacker cannot hold a sudo session, this neutralizes the most common privilege-escalation shape even when the vulnerable plugin's own permission check is broken. It is off by default and intentionally narrow: it fires only for *new* administrator/super-admin grants (never low-privilege roles, demotions, or idempotent re-grants), it defers on CLI/Cron/XML-RPC and on Unrestricted REST Application-Password surfaces, and it **cannot** see administrator capabilities conferred at runtime via the `user_has_cap`/`map_meta_cap` filters or written directly with `$wpdb`. Enable it with `add_filter( 'wp_sudo_guard_escalation', '__return_true' )`; allowlist trusted provisioners with `wp_sudo_allow_escalation` or the `WP_SUDO_ALLOW_ESCALATION` constant.
36
+
37
+
**Otherwise, no, if the exploit runs through the plugin's own path.** Apart from that opt-in administrator/super-admin guard, if the vulnerable plugin calls `wp_set_role()` (to a non-admin role), `wp_insert_user()`, or similar WordPress functions from inside its own AJAX handler or REST endpoint — without routing through a standard surface WP Sudo has been positioned to intercept — the gate never fires. WP Sudo cannot invent interception points for code it does not see.
36
38
37
39
**No, if the attack runs inside an already-active sudo session.** If the exploited browser session already has an active sudo window, WP Sudo will generally not re-challenge until that window expires. The outcome at that point depends entirely on the underlying authorization logic in the exploited code. See the next question.
38
40
@@ -113,7 +115,7 @@ change live gate state.
113
115
114
116
Users with the `manage_wp_sudo` capability. On a new install, the activating admin receives all four governance capabilities automatically. Other administrators can be granted access from **Settings → Sudo → Access**.
115
117
116
-
In compatibility mode (`wp_sudo_governance_mode = compatibility`), access falls back to `manage_options`(or `manage_network_options` on multisite). Compatibility mode is an opt-in fallback — the default is strict mode, which requires `manage_wp_sudo` explicitly.
118
+
Governance is always strict since 4.0.0: access requires the `manage_wp_sudo` capability explicitly, with no `manage_options`fallback. (The `compatibility` governance mode and the `wp_sudo_governance_mode` option were removed in 4.0.0.) On multisite, super admins are always treated as holding the governance capabilities via the `is_super_admin()` short-circuit in `wp_sudo_can()`.
-~~WPGraphQL persisted-query strategy~~ — `wp_sudo_wpgraphql_classification` filter enables external mutation classification for persisted-query setups; `str_contains` heuristic preserved as fallback.
200
-
-~~WSAL sensor bridge~~ — `bridges/wp-sudo-wsal-sensor.php`now maps all 11 audit hooks to structured WSAL events (IDs 1900001–1900011); inert when WSAL absent.
200
+
-~~WSAL sensor bridge~~ — `bridges/wp-sudo-wsal-sensor.php` maps 11 audit hooks to structured WSAL events (IDs 1900001–1900011); inert when WSAL absent. (The audit-hook total has since grown — see `docs/current-metrics.md`; newer hooks like `wp_sudo_escalation_blocked` are not yet bridged.)
201
201
202
202
### ✓ Completed in v2.10.0
203
203
@@ -549,7 +549,7 @@ not context retrieval.
549
549
With the WordPress 7.0 compatibility release and v3.4.0 hardening work closed,
550
550
the recommended implementation order is:
551
551
552
-
1.**Deprecate `compatibility` governance mode** (break-glass containment now ✅ shipped) — Two paired governance security-debt items. (a) *Still open:*fire `_doing_it_wrong()` + persistent admin notice when `wp_sudo_governance_mode = 'compatibility'` is active; update FAQ and developer reference; queue removal for the next major release. (b) ✅ *Shipped in v3.4.0:* the break-glass path that replaces it is hardened — the grant is role-gated to administrators, a non-dismissible notice renders, and the `wp_sudo_recovery_mode_active` audit hook fires (stored as a sampled `recovery_mode` event), so it is explicit, auditable, and bounded (see §12.1 Phase R3). `WP_SUDO_RECOVERY_MODE` is the only supported break-glass path going forward, and it is now sound; compatibility mode can be removed once (a) lands. **Effort:** Low (deprecation remaining)
552
+
1.**Deprecate `compatibility` governance mode** (✅ resolved) — Two paired governance security-debt items. (a) ✅ *Resolved in v4.0.0:*rather than a deprecation cycle, the `compatibility` mode and the `wp_sudo_governance_mode` option were **removed outright** in 4.0.0 — governance is always strict, and the inert option is auto-removed with a one-time dismissible notice and a `wp_sudo_inert_governance_mode_detected` audit event. (b) ✅ *Shipped in v3.4.0:* the break-glass path that replaces it is hardened — the grant is role-gated to administrators, a non-dismissible notice renders, and the `wp_sudo_recovery_mode_active` audit hook fires (stored as a sampled `recovery_mode` event), so it is explicit, auditable, and bounded (see §12.1 Phase R3). `WP_SUDO_RECOVERY_MODE` is the only supported break-glass path going forward, and it is now sound; compatibility mode can be removed once (a) lands. **Effort:** Low (deprecation remaining)
553
553
2.**Monitor and tune E2E CI acceleration without reducing release assurance**
554
554
- Explicit CI groups now split the former long challenge shard across behavior-focused jobs
555
555
- Keep the full Playwright suite available for release-grade confidence, but shorten normal feedback loops
@@ -1064,8 +1064,8 @@ SBOM, accessibility roadmap) are documented in the [CHANGELOG](../CHANGELOG.md).
1064
1064
1065
1065
### ✓ Shipped
1066
1066
1067
-
**~~WP Activity Log (WSAL) Sensor Extension~~** — shipped v2.11.0 as `bridges/wp-sudo-wsal-sensor.php`. It now maps all 11 audit hooks to WSAL events (IDs 1900001–1900011). Inert when WSAL absent.
1068
-
**~~Stream bridge~~** — implemented on `main` for v2.12.0 as `bridges/wp-sudo-stream-bridge.php`. Optional mu-plugin mapping for all 11 audit hooks.
1067
+
**~~WP Activity Log (WSAL) Sensor Extension~~** — shipped v2.11.0 as `bridges/wp-sudo-wsal-sensor.php`. It maps 11 audit hooks to WSAL events (IDs 1900001–1900011); the audit-hook total has since grown (see `docs/current-metrics.md`), so newer hooks such as the 4.1.0 `wp_sudo_escalation_blocked` are not yet mapped (tracked under Escalation guard follow-ups). Inert when WSAL absent.
1068
+
**~~Stream bridge~~** — implemented on `main` for v2.12.0 as `bridges/wp-sudo-stream-bridge.php`. Optional mu-plugin mapping for those 11 audit hooks (same coverage caveat as the WSAL bridge).
1069
1069
**~~WP-CLI `wp sudo` commands~~** — implemented on `main` for v2.12.0 (`status`, `revoke --user`, `revoke --all`).
1070
1070
**~~Public `wp_sudo_check()` / `wp_sudo_require()` API~~** — implemented on `main` for v2.12.0 for third-party action gating integrations.
1071
1071
**~~Multi-Dimensional Rate Limiting (IP + User)~~** — shipped v2.13.0. Per-IP tracking via transients alongside per-user tracking, combined lockout policy, and the triggering IP address added as the third `wp_sudo_lockout` hook argument.
0 commit comments