Advanced Custom Fields version 6.2.5 is now available.
This release is a security fix release containing an important change you need to be aware of before you update, and prepares for a change to the output of the_field
coming soon to ACF.
From ACF 6.2.5, use of the ACF Shortcode to output an ACF field will be escaped by the WordPress HTML escaping function wp_kses.
This has potential to be a breaking change if you’re using the shortcode ([acf field="field_name"]
) to output potentially unsafe HTML such as scripts or iframes for textarea or WYSIWYG fields.
At ACF, we take security very seriously, but we also consider the impact that security fixes can have on your sites. To help site owners that are impacted by this release identify what fields are affected, the plugin will display a notice in WordPress admin screens, alerting you whenever some output has been escaped by this change.
From ACF 6.2.7, expected in February 2024, escaping unsafe HTML will also apply to other functions where ACF handles outputting the value of a field, namely the the_field()
and the_sub_field()
functions. To help get ahead of the impact of this future change, we’ve also added a notice in ACF 6.2.5 alerting you that your site is outputting HTML that will be altered by the escaping coming in 6.2.7.
This fix is necessary due to a vulnerability where users on your site with the role of contributor or higher, who do not have the unfiltered_html
permission usually reserved for administrators, can manually set the value of a custom meta item outside of ACF to contain malicious HTML. Because of the vector, our usual sanitization on the save action will not apply. They could then use the ACF shortcode to output that HTML in an unsafe manner.
ACF 6.2.5 will detect when unsafe HTML has been removed from a field value output by the ACF Shortcode. An error message will be displayed in the WordPress admin, listing the fields which have been affected by this change, helping you diagnose where you may need to make fixes.
We’d like to thank Francesco Carlucci and the Wordfence team for the responsible disclosure of this vulnerability specific to the ACF Shortcode.
the_field()
When testing the above change to resolve the vulnerability, we realized there were further actions we could take to improve security when ACF handles the output of a field. Specifically, the functions the_field()
and the_sub_field()
should also be made HTML safe by default.
Whilst we’re aware many users store HTML in fields which they do want rendered to the front-end, as these functions do not allow users to apply any escaping themselves, we feel it’s our responsibility to ensure any output from these is safe.
From ACF 6.2.5, we begin detecting when the escaped value is different from the currently output value, indicating that something is being removed from a field’s value. A list of affected fields and how they’re being output is shown as a message in the WordPress admin. This message is visible to every user of your admin, but the details of the field names and functions are only visible to users with the ability to use ACF admin screens.
In ACF 6.2.7, currently expected to release in late February 2024, we will change this behavior to strip unsafe HTML by default when the_field()
or the_sub_field()
, showing an error in WordPress admin when this has happened.
To be clear, we are not deprecating or removing the_field()
or the_sub_field()
, we are just ensuring it can only output safe HTML by default.
By default, most HTML is considered safe. Things like images or tables present no risk and so the WordPress kses system which powers this escaping allows it by default. Only HTML which could be used for malicious purposes, such as <script>
tags, or <iframe>
tags are removed, and this is additionally configurable.
The list of allowed HTML and attributes is visible in the WordPress source code and includes the majority of HTML elements, except for iframes and scripts which can cause the browser to run third-party code.
We also pass the acf
context to wp_kses
, so if you wish to expressly allow certain HTML tags only for ACF, you can define this as detailed in our HTML escaping documentation.
As a developer with ACF, we’re aware you may have a use case of storing HTML which needs to be output in an unsafe manner, such as using a Text Area field to store the full <script>
tags which should be output to allow your users to edit this.
In these cases—and if you’re confident you can trust every user registered on your site with contributor or higher access—we recommend you use echo get_field()
to output this unsafe HTML to ensure it’s not filtered.
For all other fields, we’d also recommend using get_field
to output the value, but making sure you apply the right escaping for the type of field you need. This is likely to be something like the wp_kses_post function, for example:
echo wp_kses_post( get_field('field_name') );
As part of these changes, we’ve also introduced some changes across ACF to enable developers to allow HTML where they need to.
We’re aware some field types are designed to output HTML. For ACF’s default field types, specifically the oEmbed field type is designed to output an <iframe>
, and the WYSIWYG field is designed to automatically handle embedding videos which may also be iframes. In the case of the WYSIWYG field, you’d still want unsafe HTML to be removed, but then allow oEmbeds to work, for example.
To support this, we’ve added a way for field types to mark that they will handle the escaping of HTML when requested, via a new parameter $escape_html
. The new parameter is available on get_field
and get_field_object
, and is passed all the way through to the fields format_value
method. This means if the field type supports handling escaping itself, setting this to true will get that escaped value. Since ACF 6.2.6, this argument can be used by developers as it will always return an escaped value
In the case of the WYSIWYG field, this means the field will escape HTML before it runs the_content
filters which handle embedding. For more information on the changes to field types which may affect third-party fields, please see our documentation for creating a field type.
Whenever we detect that escaping the field value has modified the output value, ACF will log data about the affected function call.
Any detected modification will trigger the log, but it may not necessarily be a breaking change. For example, &
become &
when escaped. This would be detected as a modification, but is unlikely to be a problem as it will still be rendered normally in the browser. In these cases you do not need to make any code changes, instead you can leave the upcoming automatic escaping to work correctly.
This log is stored as an option in the wp_options
table. Whenever this log contains entries, the notices in WordPress admin will be shown for all users with the “Editor” role and higher by default. Users with the ability to manage ACF will have the option to view the full details. Users without the ability to manage ACF will be asked to contact their site admin about the error.
Admin users have the ability to dismiss the message, which will also clear the log. Dismissing the notice after you’ve made fixes will allow you to verify you’ve fixed every instance, as the message will not return after the affected pages have been loaded.
If you want to disable the error messages entirely, this is also possible via the following filter:
add_filter( 'acf/admin/prevent_escaped_html_notice', '__return_true' );
This filter will also disable the log being populated when set to true. You can hide the notice on admin pages while retaining the log system on the front-end by ensuring you only add the filter in an is_admin()
check, and including the necessary logic to limit it to specific users or roles.
The logic between the shortcode vulnerability fix and the_field
change is similar, and debugging instances where we will strip (from ACF 6.2.7) or are currently stripping in the case of the shortcode is the same.
ACF fires two new actions, acf/removed_unsafe_html
and acf/will_remove_unsafe_html
.
These actions provide 4 different parameters:
$function
– This is the name of the function triggering the action, acf_shortcode
, the_field
or the_sub_field
.
$selector
– This is the selector that was passed to the function. This matches what is sent in by your theme (or the shortcode).
$field
– This is the computed full field object for the request object. This will contain the field key, type and other information which can help you find the affected code in your theme.
$post_id
– This will be the $post_id provided to the function. This may be false if it’s not provided when the current global post ID is used.
Attaching a function to this action in debugging would allow you to access functions like debug_print_backtrace or Xdebug’s xdebug_break functions on your development environments if you need to find more information on exactly where in your theme or custom code the unsafe HTML is removed during output. We’ve produced a demo WordPress plugin which adds additional debug logging to your PHP error log as an example of this.
If you trust your users with the role of contributor or higher, it is possible to use one of two new filters to disable this automatic escaping by returning true. You should limit the filter to specific field keys using the additional parameters available.
acf/shortcode/allow_unsafe_html
will disable the escaping for the shortcode.acf/the_field/allow_unsafe_html
will disable the escaping when using the_field
.The filters provide different arguments should you wish to allow unsafe HTML for a specific field type, on a specific page, or for a specific field name or key.
The shortcode filter provides you the field type and the full attributes array passed into the shortcode, along with the full field object if available:
apply_filters( 'acf/shortcode/allow_unsafe_html', false, $attributes, $field_type, $field_object )
For example, if you’re using [acf field="podcast_iframe"]
to output an iframe, you could use the following code to allow that field to output potentially unsafe HTML (the iframe)
add_filter( 'acf/shortcode/allow_unsafe_html', function ( $allowed, $atts ) {
if ( $atts['field'] === 'podcast_iframe' ) {
return true;
}
return $allowed;
}, 10, 2 );
The filter for the_field()
(and the_sub_field()
) provides you with the field selector provided to the output function, the post ID (if provided), and the field type. It also provides you the field object which will contain the field key (but may be false if ACF wasn’t able to find the field reference).
apply_filters( 'acf/the_field/allow_unsafe_html', false, $selector, $post_id, $field_type, $field_object )
For example, If you’ve got a field called google_maps_iframe
which contains an iframe
of a google map, the follow code would allow it to still be output by the_field
:
add_filter( 'acf/the_field/allow_unsafe_html', function( $allowed, $selector ) {
if ( $selector === "google_maps_iframe" ) {
return true;
}
return $allowed;
}, 10, 2);
If you’re not using ACF to store unsafe HTML, or you’re confident you’re already securely escaping your output where necessary, you can opt in to the new behavior now using the new acf/the_field/escape_html_optin
filter:
add_filter( 'acf/the_field/escape_html_optin', '__return_true' );
This will enable stripping unsafe HTML immediately, and report an error in the WordPress admin when this happens.
All versions of ACF before ACF 6.2.5 are vulnerable to the reported shortcode vulnerability, so we recommend you upgrade immediately.
Additionally, we recommend disabling the ACF Shortcode entirely if you do not use it.
We’re aware you may have questions on these changes and are ready to support you. This Friday’s ACF Chat Fridays (Friday 19th January, 3pm UTC), and the following one (Friday 2nd February, 3pm UTC) will be dedicated to answering any questions you may have on this.
As a result of this security bug fix release, the previously announced changes to requiring an active license to use ACF PRO features have been delayed.
👨💻 Please find the release notes below. For the latest ACF news, follow us on Twitter @wp_acf.
ACF Free and PRO: <6.2.5
the_field()
changes as part of this security release, using the notification system from the shortcode, further delaying this release by an additional week.wp_kses
, escaping unsafe HTML. This may be a breaking change to your site but is required for security, a message will be shown in WordPress admin if you are affected. Thanks to Francesco Carlucci via Wordfence for the responsible disclosure.the_field
and the_sub_field
may require theme changes to your site to avoid stripping unsafe HTML.acf/the_field/escape_html_optin
when using the_field
and the_sub_field
before this becomes default in an upcoming ACF release.For support with the changes introduced in ACF 6.2.5, please contact our support team rather than the comments below.
For questions and help about this release, please contact our support team.
For plugin support, please contact our support team directly, as comments aren't actively monitored.