Advanced Custom Fields is a popular WordPress plugin for developers. The free version has over 2 million active installations. The “PRO” version adds an untold number more.
The plugin, owned by WP Engine, sees frequent updates. Most consist of adding new features and squashing bugs. However, a recent announcement got the WordPress community’s attention.
Version 6.2.5 of ACF (released on January 16, 2024) has begun escaping potentially unsafe HTML output in the plugin’s shortcode. The idea is to prevent malicious iframes and JavaScript from compromising a website. And it requires the attention of developers and website owners.
Here’s a quick example of the potential impact:
Suppose your website has a custom field for inputting an embed code from Google Maps. The code consists of an iframe that displays the map on your page.
Users who display this field’s output via ACF’s shortcode will notice a change. The custom field will now filter out the iframe – leaving the output broken.
But that’s not all. ACF 6.2.7 (coming February 2024) will add HTML escaping to PHP theme templates as well. Thus, you may need to update your code to keep things working.
Curious about what this change means for you? We’ve enlisted an expert who’s got the inside scoop on ACF’s new security feature.
Q&A with ACF Developer Liam Gladdy
Liam Gladdy is part of ACF’s development team. He was kind enough to answer some key questions regarding this change. He also filled us in on the backstory and offered tips for developers.
Our interview has been lightly edited for brevity and clarity.
The WP Minute: In a nutshell, can you tell us why this change is taking place?
Liam Gladdy: ACF has traditionally relied on sanitization on save to ensure potentially unsafe HTML, such as iframes or script tags, couldn’t be saved and rendered from an ACF field for non-admin users.
Last December, we received a proof of concept vulnerability where an editor without admin permissions could use another WordPress-provided method of updating post meta which would bypass all of our protection. This means we have to make sure we also escape on output as well. Indeed, this is good practice for any developer. But historically ACF has relied on being a developer tool – assuming users would handle escaping themselves.
The two functions that are changing, `the_field` and `the_sub_field` currently give users no way to easily escape the output. We believe it’s our responsibility to ensure our users are safe by default whenever ACF handles any output to the browser.
We’ve also applied the escaping to the ACF shortcode. But because that is easier to exploit by malicious contributors, we had to enable the escaping on that immediately in ACF 6.2.5, rather than giving notice of the change like we are with the functions.
TWPM: Who will be impacted by the change and when can we expect to see it?
LG: Developers who are using `the_field` or `the_sub_field` to output potentially unsafe HTML, such as iframe or script tags, are likely to be affected. This is typically in ACF textarea or WYSIWYG fields.
The ACF 6.2.5 release starts detecting when any modification will take place when this is enabled in a release towards the end of February. An admin notice is displayed listing the fields that will be modified. But in most cases, these modifications are harmless and actually beneficial.
For example, `&` characters will become `&`, which is likely what the developer intended all along. However, this is still detected as a modification from the current output.
Specifically, we’re modifying the two affected functions to run their output through the WordPress kses system by default.
TWPM: Developers use Advanced Custom Fields to display all sorts of data – including HTML. What concerns should we have about this practice?
LG: It’s perfectly fine to use ACF fields to store HTML. I’ve done so for many years on my own sites. But developers should consider what escaping should apply each time they output a field.
The best way to handle this is using `get_field` and `get_sub_field`, then manually using a WordPress escaping function that suits the type of data being output.
We’ve opted to use the same filtering level that WordPress applies to the main post content for users without the `unfiltered_html` permission by default.
TWPM: How will we know if our website is impacted by this change?
LG: After upgrading to ACF 6.2.5, ACF will log whenever it outputs a field value on the front end of your website that will be modified after this change is enabled. This log then appears as a warning notice in the WordPress admin.
For almost all instances we’ve seen so far in support, these warnings are purely the encoding of HTML entities, such as quotes or ampersands. Users will not need to make any modifications to their code at all. But, we need to report these in case a developer is using `the_field` to output a value in something like JavaScript or a data attribute where it shouldn’t be encoded.
TWPM: Some users have custom fields that include potentially unsafe HTML, such as an iframe or JavaScript. How can they ensure it keeps working properly after the change?
LG: There are two ways forward if you do want to output potentially unsafe HTML from ACF field values:
- Firstly, you could swap to using `echo get_field()` for that specific field. We don’t want to encourage this as a find/replace fix for every instance of `the_field` though, as properly escaping your output is important where fields shouldn’t contain HTML.
- Secondly, there’s a new filter we’ve added, `acf/the_field/allow_unsafe_html`. This filter is documented in our release post and provides the field being output, the field type and the full field object (which contains the value) – returning true from that function will mark the field as safe for HTML output. We recommend you only allow unsafe HTML for specific fields for security.
TWPM: Is there anything else developers should be looking out for?
LG: Our post for this release should answer the majority of questions users have about this change, and our support team is ready to answer any other questions.
The ACF development team runs bi-weekly office hours at 3PM GMT and we’ll be focusing our next session on Friday, February 2 on these changes should anyone want to ask us questions directly. You can register at https://www.advancedcustomfields.com/acf-chat-fridays/ for this.
We’ve also published some sample code that developers can drop into their functions.php or a plugin on development sites which will log much more detail (such as templates, and previous/escaped values) whenever we detect escaping will occur. We don’t do this by default because it could have significant performance implications on a production site.
Overall though, this change is a significant leap forward in the default security provided by ACF and removes the ability for developers to accidentally introduce vulnerabilities into their websites. We’re confident making this change is an overall significant positive step forward for both our users and the wider WordPress ecosystem.
Change Is a Constant of Web Development
Web security is one of the paramount issues for developers. We evolve as new threats and best practices emerge. The process for remediation isn’t always straightforward, though.
Plugin developers can only do so much. Users also must pitch in and clean up their code. Such is the case with these changes to Advanced Custom Fields.
We should also note that this isn’t the only change coming to ACF. In the future, unlicensed copies of the ACF PRO plugin will disable editing of premium features. Custom field data will continue to display on the front end. However, make sure your copy is licensed if you want to make changes to your field configurations.
Our thanks to Liam Gladdy for taking the time to speak with us! You can connect with him on X/Twitter or the ACF Blog.
Join The Newsletter
Get your favorite 5 minutes of WordPress news for busy professionals every week — 100% Free! Join the WP Minute Newsletter below 👇