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
- Review REST registrations for privileged callbacks that lack robust `permission_callback` checks and instead rely on request headers.
448
448
- Look for usages of core user-management functions (`wp_insert_user`, `wp_create_user`) inside REST handlers that are gated only by header values.
449
449
450
-
Hardening
451
-
452
-
- Never derive authentication or authorization from client-controlled headers.
453
-
- If a reverse proxy must inject identity, terminate trust at the proxy and strip inbound copies (e.g., `unset X-Wcpay-Platform-Checkout-User` at the edge), then pass a signed token and verify it server-side.
454
-
- For REST routes performing privileged actions, require `current_user_can()` checks and a strict `permission_callback` (do NOT use `__return_true`).
WordPress themes and plugins frequently expose AJAX handlers through the `wp_ajax_` and `wp_ajax_nopriv_` hooks. When the **_nopriv_** variant is used **the callback becomes reachable by unauthenticated visitors**, so any sensitive action must additionally implement:
@@ -511,31 +502,6 @@ Other impactful targets include plugin/theme `.php` files (to break security plu
511
502
* Concatenation of unsanitised user input into paths (look for `$_POST`, `$_GET`, `$_REQUEST`).
512
503
* Absence of `check_ajax_referer()` and `current_user_can()`/`is_user_logged_in()`.
> **Always** treat any write/delete operation on disk as privileged and double-check:
537
-
> • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via `realpath()` plus `str_starts_with()`).
538
-
539
505
---
540
506
541
507
### Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
@@ -565,12 +531,6 @@ Why it’s exploitable
565
531
- If a user previously had higher privileges saved in `_asenha_view_admin_as_original_roles` and was downgraded, they can restore them by hitting the reset path.
566
532
- In some deployments, any authenticated user could trigger a reset for another username still present in `viewing_admin_as_role_are` (broken authorization).
567
533
568
-
Attack prerequisites
569
-
570
-
- Vulnerable plugin version with the feature enabled.
571
-
- Target account has a stale high-privilege role stored in user meta from earlier use.
572
-
- Any authenticated session; missing nonce/capability on the reset flow.
573
-
574
534
Exploitation (example)
575
535
576
536
```bash
@@ -591,21 +551,6 @@ Detection checklist
591
551
- Modify roles via `add_role()` / `remove_role()` without `current_user_can()` and `wp_verify_nonce()` / `check_admin_referer()`.
592
552
- Authorize based on a plugin option array (e.g., `viewing_admin_as_role_are`) instead of the actor’s capabilities.
593
553
594
-
Hardening
595
-
596
-
- Enforce capability checks on every state-changing branch (e.g., `current_user_can('manage_options')` or stricter).
597
-
- Require nonces for all role/permission mutations and verify them: `check_admin_referer()` / `wp_verify_nonce()`.
598
-
- Never trust request-supplied usernames; resolve the target user server-side based on the authenticated actor and explicit policy.
599
-
- Invalidate “original roles” state on profile/role updates to avoid stale high-privilege restoration:
- Removed the insecure fallback from $_POST['id']; $user_email must originate from verified provider branches in switch($_POST['using']).
854
799
800
+
## Unauthenticated privilege escalation via REST token/key minting on predictable identity (OttoKit/SureTriggers ≤ 1.0.82)
801
+
802
+
Some plugins expose REST endpoints that mint reusable “connection keys” or tokens without verifying the caller’s capabilities. If the route authenticates only on a guessable attribute (e.g., username) and does not bind the key to a user/session with capability checks, any unauthenticated attacker can mint a key and invoke privileged actions (admin account creation, plugin actions → RCE).
- Any route that issues tokens/keys based on request-supplied identity (username/email) without tying to an authenticated user or capability
831
+
- Look for subsequent routes that accept the minted token/key without server-side capability checks
832
+
833
+
Hardening
834
+
- For any privileged REST route: require permission_callback that enforces current_user_can() for the required capability
835
+
- Do not mint long-lived keys from client-supplied identity; if needed, issue short-lived, user-bound tokens post-authentication and recheck capabilities on use
836
+
- Validate the caller’s user context (wp_set_current_user is not sufficient alone) and reject requests where !is_user_logged_in() || !current_user_can(<cap>)
Nonces prevent CSRF, not authorization. If code treats a nonce pass as a green light and then skips capability checks for privileged operations (e.g., install/activate plugins), unauthenticated attackers can meet a weak nonce requirement and reach RCE by installing a backdoored or vulnerable plugin.
843
+
844
+
- Vulnerable path: plugin/install_and_activate
845
+
- Flaw: weak nonce hash check; no current_user_can('install_plugins'|'activate_plugins') once nonce “passes”
846
+
- Impact: full compromise via arbitrary plugin install/activation
847
+
848
+
PoC (shape depends on plugin; illustrative only)
849
+
850
+
```bash
851
+
curl -i -s -X POST https://victim.tld/wp-json/<fk-namespace>/plugin/install_and_activate \
--data-urlencode "s=' UNION SELECT user_login,user_pass FROM wp_users-- -"
882
+
```
883
+
884
+
Detection checklist
885
+
- Grep for depicter-* action handlers and direct use of $_GET['s'] or $_POST['s'] in SQL
886
+
- Review custom queries passed to $wpdb->get_results()/query() concatenating s
887
+
888
+
Hardening
889
+
- Always use $wpdb->prepare() or wpdb placeholders; reject unexpected metacharacters server-side
890
+
- Add a strict allowlist for s and normalize to expected charset/length
891
+
892
+
---
893
+
894
+
## Unauthenticated Local File Inclusion via unvalidated template/file path (Kubio AI Page Builder ≤ 2.5.1)
895
+
896
+
Accepting attacker-controlled paths in a template parameter without normalization/containment allows reading arbitrary local files, and sometimes code execution if includable PHP/log files are pulled into runtime.
-[Unpatched Privilege Escalation in Service Finder Bookings Plugin](https://patchstack.com/articles/unpatched-privilege-escalation-in-service-finder-bookings-plugin/)
865
927
-[Service Finder Bookings privilege escalation – Patchstack DB entry](https://patchstack.com/database/wordpress/plugin/sf-booking/vulnerability/wordpress-service-finder-booking-6-0-privilege-escalation-vulnerability)
866
-
867
928
-[Unauthenticated Broken Authentication Vulnerability in WordPress Jobmonster Theme](https://patchstack.com/articles/unauthenticated-broken-authentication-vulnerability-in-wordpress-jobmonster-theme/)
929
+
-[Q3 2025’s most exploited WordPress vulnerabilities and how RapidMitigate blocked them](https://patchstack.com/articles/q3-2025s-most-exploited-wordpress-vulnerabilities-and-how-patchstacks-rapidmitigate-blocked-them/)
0 commit comments