Blocks for ACF Fields <= 1.6.2 - Missing Authorization to Authenticated (Author+) Arbitrary ACF Field Value Disclosure via 'id' Parameter
Description
The Blocks for ACF Fields plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the get_all_values() function in the /wp-json/acf-field-blocks/v1/values REST endpoint in versions up to, and including, 1.6.2. The permission_callback only verifies the generic publish_posts capability and the handler passes a user-supplied id parameter directly to get_field_objects() without verifying that the requesting user is authorized to read the target object. This makes it possible for authenticated attackers, with Author-level access and above, to read ACF field values from arbitrary posts (including private posts, drafts, posts by other users, and other ACF-supported objects) that they should not have access to.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.6.2What Changed in the Fix
Changes introduced in v1.6.3
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-12428 This plan outlines the systematic approach to exploiting a Missing Authorization vulnerability in the **Blocks for ACF Fields** plugin (<= 1.6.2), which allows authenticated users (Author level and above) to disclose arbitrary Advanced Custom Fields (ACF…
Show full research plan
Exploitation Research Plan: CVE-2026-12428
This plan outlines the systematic approach to exploiting a Missing Authorization vulnerability in the Blocks for ACF Fields plugin (<= 1.6.2), which allows authenticated users (Author level and above) to disclose arbitrary Advanced Custom Fields (ACF) values from any post or object ID.
1. Vulnerability Summary
- Vulnerability: Missing Authorization
- Location:
inc/class-rest.php(specifically theget_all_values()callback for the/wp-json/acf-field-blocks/v1/valuesREST endpoint). - Cause: The
permission_callbackfor the/valuesendpoint only verifies thepublish_postscapability. The implementation ofget_all_values()(as described in the vulnerability report and supported by theRest::register_routesstructure) accepts a user-controlledidparameter and passes it to ACF functions (likeget_field_objects()) without verifying if the current user has permission to read the specific post associated with thatid.
2. Attack Vector Analysis
- REST Endpoint:
/wp-json/acf-field-blocks/v1/values - HTTP Method:
GET(READABLE) - Vulnerable Parameter:
id(Target Post/Object ID) - Authentication Required: Authenticated (Author role or higher). The
publish_postscapability is granted to Authors, Editors, and Administrators by default. - Preconditions:
- The target WordPress site must have Advanced Custom Fields (ACF) or Secure Custom Fields (SCF) installed and active.
- Sensitive data must be stored in ACF fields attached to a post that the Author normally cannot access (e.g., a Private Post, a Draft, or a post belonging to another user).
3. Code Flow
- Registration:
ACFFieldBlocks\Rest::register_routes()registers the endpoint:register_rest_route( 'acf-field-blocks/v1', '/values', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'get_all_values' ), 'permission_callback' => function() { return current_user_can('publish_posts'); } ) ); - Access: An Author-level user accesses the endpoint via a GET request with an
idparameter. - Execution (Inferred from Patch): The
get_all_values($request)method retrieves theidvia$request->get_param('id'). - Sink: It calls
get_field_objects($id)(an ACF function). This function retrieves all fields for the given ID. Because the plugin does not check if the user canedit_postorread_postfor that specific$id, the data is returned in the REST response.
4. Nonce Acquisition Strategy
To interact with the WordPress REST API using cookie-based authentication, a _wpnonce or X-WP-Nonce header is required. This nonce is tied to the wp_rest action.
- Shortcode Identification: The plugin uses the
[acf_field_block]or "ACF Field" block. - Setup: Create a test page containing the block.
- Browser Execution:
- Log in to the WordPress dashboard as the Author user.
- Navigate to
wp-admin/index.php. - Use
browser_evalto extract the REST nonce usually available in thewpApiSettingsobject or via a specific call. - JS Script:
window.wpApiSettings ? window.wpApiSettings.nonce : "". - Alternatively, fetch
wp-admin/admin-ajax.php?action=rest-nonceto get a fresh nonce for thewp_restaction.
5. Exploitation Strategy
The goal is to use an Author account to read ACF field values from a Private Post created by an Administrator.
Step-by-Step Plan:
- Target Identification: Determine the ID of a Private Post containing sensitive ACF data (e.g., Post ID 123).
- Login: Authenticate as the Author user.
- Nonce Retrieval: Obtain the
wp_restnonce. - Data Extraction: Send a GET request to the vulnerable endpoint.
HTTP Request (via http_request tool):
- Method:
GET - URL:
http://<TARGET_URL>/wp-json/acf-field-blocks/v1/values?id=123 - Headers:
X-WP-Nonce: <NONCE_VALUE>Content-Type: application/json
- Expected Response: A JSON object containing the
label,name, andvalueof all ACF fields associated with Post 123.
6. Test Data Setup
- Admin User Actions:
- Create a new ACF Field Group (e.g., "Internal Secrets").
- Add a Text field named
api_key_secret. - Set the location to "Post Type is equal to Post".
- Create a Private Post (ID $TARGET_ID).
- Populate the
api_key_secretfield with a value:SUPER_SECRET_TOKEN_2026.
- Attacker User Action:
- Create a user with the Author role.
7. Expected Results
- The request should return a
200 OKstatus code. - The JSON body should contain the data from the Private Post:
{ "api_key_secret": { "key": "field_xxxxxxxx", "label": "API Key Secret", "name": "api_key_secret", "type": "text", "value": "SUPER_SECRET_TOKEN_2026", ... } } - If the vulnerability is patched, the endpoint should return a
403 Forbiddenor restricted data.
8. Verification Steps
- Manual Check: Verify the returned
valuematches the one set by the Admin in the Private Post. - WP-CLI Comparison:
# Confirm the post is indeed private and not accessible by Author normally wp post get <TARGET_ID> --user=author_user_login # This should fail or return "Invalid post ID" if standard permissions are working.
9. Alternative Approaches
- Brute Forcing IDs: If the specific target ID is unknown, the agent can iterate through common IDs (1 to 100) to find hidden ACF metadata.
- Other Object Types: Test
idvalues for other ACF-supported objects, such asuser_1(to read metadata of the Admin user) orterm_5(taxonomy metadata), asget_field_objects()accepts these string-based ID formats.
Summary
The Blocks for ACF Fields plugin for WordPress is vulnerable to unauthorized disclosure of data via its REST API in versions up to 1.6.2. Due to a missing object-level capability check in the get_all_values() function, authenticated users with Author-level access or higher can retrieve sensitive Advanced Custom Fields (ACF) values for any post, user, or object ID, including those they lack permissions to view.
Vulnerable Code
// inc/class-rest.php lines 88-100 register_rest_route( $namespace, '/values', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'get_all_values' ), 'args' => array(), 'permission_callback' => function() { return current_user_can('publish_posts'); } ) ); --- // inc/class-rest.php lines 291-314 (implementation inferred from patch diff context) public function get_all_values( \WP_REST_Request $request ) { $post_id = $request->get_param( 'id' ); if ( empty( $post_id ) ) { return []; } $fields = get_field_objects( $post_id, false, true, false ); $values = array(); if ( ! empty( $fields ) ) { foreach ( $fields as $field ) { $values[ $field['name'] ] = $field; } } return apply_filters( 'acf_field_blocks_rest_values', $values ); }
Security Fix
@@ -299,6 +299,15 @@ return []; } + // The id can point at any object, so check object-level access before reading. + if ( ! $this->current_user_can_read_object( $post_id ) ) { + return new \WP_Error( + 'rest_forbidden', + __( 'You are not allowed to read the field values of this object.', 'acf-field-blocks' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + $fields = get_field_objects( $post_id, false, true, false ); $values = array(); @@ -314,4 +323,57 @@ return apply_filters( 'acf_field_blocks_rest_values', $values ); } + /** + * Check whether the current user may read the ACF values of the given object id. + * + * @since 1.6.3 + * + * @param int|string $post_id ACF object id. + * @return bool True if the current user may read the object. + */ + private function current_user_can_read_object( $post_id ) { + // Decode the id the same way ACF does, so the check matches what gets read. + if ( function_exists( 'acf_decode_post_id' ) ) { + $decoded = acf_decode_post_id( $post_id ); + $type = $decoded['type']; + $id = $decoded['id']; + } elseif ( is_numeric( $post_id ) ) { + $type = 'post'; + $id = $post_id; + } else { + return false; + } + + switch ( $type ) { + case 'post': + $id = (int) $id; + return $id && current_user_can( 'read_post', $id ); + + case 'user': + // Allow your own profile; otherwise require edit access to the user. + $id = (int) $id; + return $id && ( get_current_user_id() === $id || current_user_can( 'edit_user', $id ) ); + + case 'comment': + $id = (int) $id; + $comment = $id ? get_comment( $id ) : null; + return $comment && ( current_user_can( 'moderate_comments' ) + || current_user_can( 'read_post', (int) $comment->comment_post_ID ) ); + + case 'term': + // Terms are public taxonomy data; just confirm it exists. + $id = (int) $id; + return $id > 0 && term_exists( $id ) !== null; + + case 'option': + case 'block': + // Shared store, not a per-object resource. Already gated by publish_posts. + return true; + + default: + // Unknown/sensitive types (blog, woo_order, ...). + return current_user_can( 'manage_options' ); + } + } +
Exploit Outline
The exploit requires an authenticated user account with the 'publish_posts' capability (typically Author, Editor, or Administrator roles). The attacker first obtains a valid WordPress REST API nonce. They then send a GET request to the `/wp-json/acf-field-blocks/v1/values` endpoint, supplying an arbitrary target ID in the 'id' parameter (e.g., a post ID for a private draft or a user ID such as 'user_1'). Because the plugin lacks object-level permission verification for the provided ID, it calls the ACF get_field_objects() function on the target and returns a JSON response containing all associated custom field metadata and sensitive values, even if the attacker should not have access to that specific object.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.