Advanced Custom Fields version 6.8.11 is now available.
This release contains several security fixes for both ACF and ACF PRO.
We recommend that all users of ACF and ACF PRO upgrade as soon as possible.
Some of these fixes change how ACF saves and displays data, and a small number of sites will need to make changes. Please read the summary below before you update, especially if you use front-end forms, the shortcode, block bindings, or custom code that adds fields to forms.
What’s Changing and Who It Affects
Fields Only Save When They Were Shown
ACF now only saves fields that were shown on the form being submitted, or whose field group’s location rules match the content being saved. This stops users from saving values for fields they were never shown.
Most sites won’t notice any difference. You may be affected if:
- Your own JavaScript adds ACF inputs to a form.
- A custom or third-party form submits ACF fields whose field group isn’t assigned to that content.
- Your registration form uses a field group with the location rule “User Form is Add / Edit”. Those fields no longer save when a user registers. Change the rule to “User Form is Register” or “All”.
ACF now also stops WordPress’s built-in Custom Fields meta box from editing meta that belongs to an ACF field. Edit those values through the ACF field instead.
If a field stops saving, first check that its field group’s location rules match where the field is used. If the field is added on purpose by custom code, allow it with the acf/form/{context}/allowed_field_keys filter. {context} is where the field is saved, such as post, user, taxonomy, or options_page. With WP_DEBUG and WP_DEBUG_LOG enabled, ACF logs each field it doesn’t save, including the context to use in the filter name.
Front-end forms created with acf_form() already only saved the fields they displayed, and this release doesn’t change that. To allow extra fields in those forms, keep using the existing acf/form/allowed_field_keys filter. Fields dropped from these forms aren’t logged.
add_filter( 'acf/form/post/allowed_field_keys', function ( $keys, $post_id ) {
$keys[] = 'field_abc123';
return $keys;
}, 10, 2 );
The Shortcode and Block Bindings No Longer Output Personal Data
The shortcode and ACF block bindings now output only the user ID for User fields, rather than the user’s name, email address, and other details.
If you use the shortcode or a block binding to show a User field, such as an author byline, it will now show the user’s ID instead of a list of their details. The best fix is to format the value into the text you want with acf/format_value:
add_filter( 'acf/format_value/name=post_contact', function ( $value ) {
return is_array( $value ) && isset( $value['display_name'] ) ? $value['display_name'] : $value;
}, 20 );
To restore the previous output completely, use the acf/bindings/allow_user_data filter. This shows the user’s personal data, including their email address, to every visitor, so only do this if that’s what you intend.
Two related changes:
- Fields that return nested data, such as an Image field set to return an Image Array, previously output a jumbled list of values. They now output nothing. Simple lists, such as Checkbox values, are unchanged.
- Fields that return post objects, such as a Relationship field, previously caused a fatal error. They now output nothing.
For either, change the field’s return format (for example, Image URL or Post ID), or use get_field() in a template.
Relationship, Post Object, and Page Link Fields Respect Read Permissions
These fields now only show posts the current user can read. Contributors and Authors no longer see other users’ draft, pending, or scheduled posts when searching, and can’t select them. Editors and Administrators aren’t affected.
If an editor has already selected a post that another user can’t read, that user sees “(Restricted item)” instead of its title. The selection is kept when they save.
In ACF Blocks, these values are checked on the front end against the author of the post the block is saved in. If a block references a post that author can’t read, such as another user’s unpublished draft, it’s left out for visitors. Usually the fix is to publish the referenced post. To turn this check off, use the acf/fields/relational/hide_unreadable_posts filter. get_field() in theme templates is unchanged.
Membership and editorial plugins that grant access to individual posts can use the acf/user_can_read_post and acf/fields/relational/unreadable_post_statuses filters.
Bidirectional Fields Check the User Can Edit the Other Side
When a user saves a bidirectional field, ACF now only adds the reference on the other side if they can edit that post, assign that term, or edit that user. Users can also be linked by anyone who can edit other people’s posts of that post type, as they could already set that user as the post’s author. If the user can’t update the other side, their own value still saves, but the other side isn’t updated.
Values saved with update_field(), WP-CLI, or cron aren’t checked. Logged-out front-end forms are checked, so they no longer update the other side of a bidirectional field. If visitors are meant to create these links, use the acf/bidirectional/can_update_target filter, scoped to the fields that need it. To mark your own code’s saves as trusted, use acf/is_trusted_save_context.
Password-Protected Posts Keep Their Field Values Hidden
Field values of password-protected posts are no longer shown by the shortcode, block bindings, JSON-LD output, or the REST API until the password has been entered. This matches how WordPress handles the post’s content, and applies to editors viewing the front end too.
Headless sites that read a protected post’s fields over the REST API need to send the post’s password parameter, or authenticate as a user who can edit the post. Relationship and Post Object fields that reference a password-protected post now return post IDs in REST responses instead of full post objects, unless the user can edit the referenced post. If any referenced post is protected, the whole field returns IDs, in the same format as ?acf_format=light.
Field Settings Saved by Users Without unfiltered_html
Settings for fields, field groups, post types, taxonomies, and options pages saved by users without the unfiltered_html capability are now sanitized. On multisite, that includes site administrators, as only Super Admins have this capability. Safe HTML such as is kept and unsafe HTML such as is removed. Administrators on single sites aren’t affected.
For those users, a field’s wrapper settings are limited to width, class, and id. Event handler attributes, such as onclick, in a field’s wrapper setting are no longer output for any field, including fields registered in PHP or local JSON. To add one on purpose, use the acf/field_wrapper_attributes filter.
This also fixes a long-standing bug where settings containing &, <, or certain HTML entities could reset a field to its default settings.
Front-End Uploads No Longer Generate Previews for Untrusted Users
Files uploaded through the basic uploader, such as in front-end forms, by users without theupload_files capability no longer generate PDF preview images or save cover art embedded in audio and video files. This includes logged-out visitors, Subscribers, and Contributors. Uploads through the Media Library aren’t affected.
If you trust the people uploading through your forms, you can turn previews back on with the acf/upload/generate_previews filter.
Restricting Who Can Add Custom Choices
Checkbox, Radio, and Select fields that save submitted custom values to the field’s choices continue to work as before. The newacf/fields/allow_append_choices filter lets you restrict who can add new choices. If visitors can submit these fields on your site, such as through a front-end form, we recommend using it.
add_filter( 'acf/fields/allow_append_choices', function () {
return current_user_can( 'edit_posts' );
} );
We’d like to thank Jakub Herman and vuxvinh, via WPScan, for the responsible disclosure of the vulnerabilities fixed in this release.
Wrap Up
👨💻 Please find the release notes below. And for the latest ACF news, follow us on Twitter @wp_acf. We take the security of ACF extremely seriously and are always working on protecting our users. If you have discovered a vulnerability in the code or have a security issue, please see our Security page for more information.Changelog
- Security – Custom values submitted to Checkbox, Radio, and Select fields with “Save Custom Values” enabled can no longer corrupt the field’s settings or add HTML attributes to the field’s wrapper. The new
acf/fields/allow_append_choicesfilter can be used to restrict who can add new choices to a field. Thanks to Jakub Herman via WPScan for the responsible disclosure - Security – ACF now sanitizes field, field group, post type, taxonomy, and options page settings saved by users without the
unfiltered_htmlcapability. For those users, a field’s wrapper settings are limited to width, class, and id. Event handler (on*) attributes in a field’s wrapper setting are no longer output for any field, including fields registered in PHP or local JSON - Security – Field values of password-protected posts are no longer shown by the
shortcode, block bindings, JSON-LD output, or the REST API until the password is entered. REST responses also no longer expand a referenced password-protected post into a full post object - Security – The
shortcode and ACF block bindings now output only user IDs for User fields, rather than personal data such as names and email addresses. The previous output can be restored with the newacf/bindings/allow_user_datafilter - Security – Files uploaded through the basic uploader by users without the
upload_filescapability no longer generate PDF preview images or save embedded audio and video cover art. This can be changed with the newacf/upload/generate_previewsfilter - Security – ACF now only saves fields that were shown for the content being saved, or whose field group’s location rules match it, preventing users from saving values for fields they were never shown. Inputs outside these rules, such as fields added with JavaScript, can be allowed with the
acf/form/{context}/allowed_field_keysandacf/options_page/allowed_field_keysfilters. Registration forms no longer save fields from field groups set to “User Form is Add / Edit”. Thanks to vuxvinh via WPScan for the responsible disclosure - Security – WordPress’s Custom Fields meta box, its AJAX handler, and XML-RPC can no longer change meta that belongs to ACF fields
- Security – Basic uploader nonces are now tied to the content being edited
- Security – The AJAX request that loads field groups while editing a post no longer returns field groups assigned to other content
- Security – The Relationship, Post Object, and Page Link fields no longer reveal the titles or statuses of posts the current user cannot read, and no longer save newly selected posts the user cannot read. Existing selections the user cannot read are shown as “(Restricted item)” and are kept when the user saves. Thanks to vuxvinh via WPScan for the responsible disclosure
- Security – Relationship, Post Object, and Page Link values rendered in ACF Blocks now leave out posts the author of the post cannot read, such as another user’s unpublished drafts. This can be disabled with the new
acf/fields/relational/hide_unreadable_postsfilter - Security – Bidirectional fields now only add references to posts the current user can edit, terms they can assign, and users they can edit or set as a post’s author. Saves made with
update_field(), WP-CLI, or cron are not checked, and the newacf/bidirectional/can_update_targetandacf/is_trusted_save_contextfilters can adjust this. Thanks to vuxvinh via WPScan for the responsible disclosure - Fix – The
shortcode and ACF block bindings no longer cause a fatal error on PHP 8 when a field returns objects, such as a Relationship field set to return post objects. These values, along with array values such as Image fields set to return an array, now output nothing - Fix – Field settings containing
&,<, or certain HTML entities no longer cause the field to revert to its default settings after saving - Fix – Saving a custom choice no longer removes backslashes from the field’s other settings