16 Jan

ACF 6.2.5 Security Release

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.

By Liam Gladdy

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.

Example screenshots of ACF 6.2.5's admin messages warning about changes to field value escaping

We’d like to thank Francesco Carlucci and the Wordfence team for the responsible disclosure of this vulnerability specific to the ACF Shortcode.

Upcoming Changes to 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.

Disallowed HTML tags

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.

How to use ACF securely

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') );

Field type changes

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.

Detection and notice information

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 &amp; 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.

Additional debugging options

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.

Conditionally disabling the new behavior

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);

Enable the new behavior early

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.

Wrapping Up

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.

Affected Versions

ACF Free and PRO: <6.2.5

Security Response Timeline

  • 2023-12-12 19:31 GMT – Initial contact from Wordfence via our support form asking us to confirm our support system was an acceptable method of disclosure.
  • 2023-12-12 19:33 GMT – Confirmation sent from our development team that they could disclose this way.
  • 2023-12-15 17:09 GMT – Disclosure received.
  • 2023-12-15 19:00 GMT – Patch built and tested, however due to the holiday season we decided to hold the release until developers were back at their desks in the new year rather than the release disclosing this vulnerability.
  • 2024-01-02 15:00 GMT – Decision taken to prepare the_field() changes as part of this security release, using the notification system from the shortcode, further delaying this release by an additional week.
  • 2024-01-16 15:00 GMT – Release of ACF 6.2.5.

Changelog

  • Security Fix – The ACF shortcode will now run all output through 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.
  • Security – ACF now warns via an admin message, when upcoming changes to the_field and the_sub_field may require theme changes to your site to avoid stripping unsafe HTML.
  • Security – Users may opt in to automatically escaping unsafe HTML via a new filter 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.

About the Author

  • aurelientalbot.web says:

    And what’s the best way? in terms of security. Thank you for your feedback.

    • Liam says:

      Each has positives and negatives. The latter one for example will allow iframes any ACF field – 1 and 2 are pretty much the same. I’d probably just opt for option 1 as it’s easier to implement and doesn’t rely on filters in another place affecting the output, so easier to maintain should another developer take over.

      • aurelientalbot.web says:

        Do the error messages disappear when the fields are corrected?

        Thanks for your feedback and help!

    • Liam says:

      If you dismiss the message, you reset the log – so only still-potentially-affected fields will show up again.

  • Jezer Mejía says:

    There’s an issue when trying to format WYSIWYG field values with the REST API with the following request: URL/wp-json/wp/v2/heroes?acf_format=standard

    Fatal error:
    Uncaught ArgumentCountError: Too few arguments to function acf_field_wysiwyg: format_value(), 3 passed in /var/www/wordpress/wp-includes/class-wp-hook.php on line 324 and exactly 4 expected in /var/www/wordpress/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-wysiwyg-php:406

    This same error happens when using the ACF to REST API plugin to request WYSIWYG values.

    • Liam says:

      Hey Jezer,

      We’ve not been able to reproduce this issue with the native ACF REST API, only with the ACF to REST API plugin installed.

      The ACF to REST API plugin makes calls to internal functions which have been modified, so they’ll need to do another release to fix, or you can swap to the ACF native API.

      If you’re seeing it without the ACF to REST API plugin enabled, there must be some other code in another plugin, or theme, that is calling format_value incorrectly.

      Thanks, Liam

  • Thabiso says:

    Hello,

    I had iFrames displayed using shortcodes on my site, and they are no longer showing. Is there a way to display them safely? Or do I just need to disable the new behaviour?

    • Liam says:

      Hey Thabiso,

      You can use the sample code in the blog post above in the section "Conditionally disabling the new behaviour" to allow specific fields to be HTML safe, and keep the rest of your fields secure.

      Thanks, Liam

  • B P says:

    What is the proper way to escape this? <img src="<?php the_field('feature_image'); ?>" alt="">

    We have a video embedded in one of the wysiwyg fields. When I replace <?php the_sub_field('text'); ?> with <?php echo wp_kses_post( get_sub_field('text') ); ?> videos don’t load.

  • Shyam Krishna Sreekumar says:

    Thanks for the details. So i have a quick question – i just tried in one of my site and could see the log triggered in the admin.

    "ACF — ACF will soon escape unsafe HTML that is rendered by the_field(). We’ve detected the output of some of your fields will be modified by this change"

    When cross checked, "&" is the culprit. But it wont cause an issue as after escaping, it will be &. So what should we do now? Ignore the admin log message ? Please advise.

    • Liam says:

      Hey Shyam,

      I’d recommend those who think they aren’t affected just enable the new behaviour early, and then disable the message. This way, you’ll see if anything is broken immediately, and can fix it. You can do this with the following two filters:

      add_filter( 'acf/the_field/escape_html_optin', '__return_true' ); and add_filter( 'acf/admin/prevent_escaped_html_notice', '__return_true' );

  • Jon Smith says:

    Hi thanks for this, just checking through various sites… please could you let me know how to change the below?

    <?php $checkout_code = get_field(’embedded_checkout_code’); if( !empty($checkout_code) ): ?> <?php echo the_field(’embedded_checkout_code’); ?> <?php endif; ?>

    Also another one

    <?php the_field( ‘podcast_embed_code’ ); ?>

    is it just a case of changing to

    <?php echo get_field( ‘podcast_embed_code’ ); ?>

    Thanks!

    • Liam says:

      The podcast embed code is right there yeh. For the first one, you can just change the current echo the_field (which is technically a bug – you’re echoing something that also echos!) to echo get_field

      • Jon Smith says:

        Thanks Liam! So just going through all my websites, it is basically just a case of changing instances of ‘the_field’ to ‘echo get_field’ to update safely?

        • Liam says:

          Hey Jon,

          If you’d prefer to just let iframes be allowed in any ACF field, but still be protected from things like scripts, you can do that with:

          add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_iframe_tag', 10, 2 );
          function acf_add_allowed_iframe_tag( $tags, $context ) {
              if ( $context === 'acf' ) {
                  $tags['iframe'] = array(
                      'src'             => true,
                      'height'          => true,
                      'width'           => true,
                      'frameborder'     => true,
                      'allowfullscreen' => true,
                  );
              }
          
              return $tags;
          }

          Or yes, you could do the the_field to echo get_field, but you only need to do that for fields which contain iframes or scripts – you shouldn’t just blanket change, otherwise you lose the security of escaping which is important. You should escape by default and disable when necessary.

          • Jon Smith says:

            It’s only a couple of sites where we use them to enter podcast or youtube embed code and maybe a map. Most would just be simple text. Only every myself or the client with access to any of these site admins so should be ok?

            Thanks very much for the replies and advice.

        • Liam says:

          Reached the comment depth limit here, so gotta reply on this one.

          Yeh, you should be okay if you only have admins you trust. We’re trying to also push good practice here for software development as part of our advise here, so that’s why we’re trying to explain that you escape all output unless it’s intended to contain unsafe.

          React for example handles this really well… if you want to provide unescaped content, you have to pass it in as dangerouslySetInnerHTML – this explicit command makes it clear every time you do it that it has potential to be dangerous, and that is what you’re doing here when you output unescaped HTML.

  • Nebojsa Lakic says:

    OK, so I have one ACF text field for the custom text with the link that leads to a page with the form to book tickets for the shows.

    That field is set to events template only, so when new event is added, that field is used for a custom text with the link (BOOK NOW).

    It’s just a simple html to add a link to "Book now" text, like this: <a href="https://www.mypage.com/event">Book Now</a>

    I’ve then added some php inside the Event template to display this Book now text link, like this:

    $title = get_field(‘book’);

    <?php if($title):?> <div class="book"><?php echo $title;?></div> <?php endif;?>

    Do I need to change something here, and if so, what? I’m not that good with PHP, I’ve found this code in some tutorial few years ago. It’s working fine for now, but I have this message in wordpress dashboard "ACF — ACF now automatically escapes unsafe HTML when rendered by the ACF shortcode. We’ve detected the output of some of your fields will be modified by this change.".

    Thanks in advance!

    • Liam says:

      Hey Nebojsa,

      I don’t think the "Book Now" field won’t be the thing causing the warning here (although, i’ll test properly next week there’s nothing that gets encoded in there – even if it does change something, it won’t be a breaking change)

      I wrote a plugin that will enable the escaping early, and disable the notifications – so if you want to actually test what will happen now and quickly turn it off if anything breaks, you can grab it from GitHub: https://github.com/lgladdy/enable-acf-escaping-disable-notification (Grab the zip from the Releases on the right hand side, then upload on your plugins page)

      If you enable it and everything is fine, feel free to just keep the plugin enabled for a few months throughout our releases that will enable this for everyone else.

  • anime container says:

    Hey, All I use for my fields is URLs and Texts only. If I don’t care about the warning or preventing it from appearing, should I add something to my code?

  • Tiny Idea says:

    Hm,

    I have activated the optin, by pasting this in my functions.php

    add_filter( ‘acf/the_field/escape_html_optin’, ‘__return_true’ );

    And i have installed the debug plugin.

    The weird thing, i have a field containing an iframe embed (youtube). Loading this page triggers the log, and it says: Escaped Value: ”

    But the youtube video still render on the page?

    Am i doing something wrong?

    • Liam says:

      Hey there, how are you viewing the error log? If you’ve got some kinda web tool on top of the raw file, it might well be hiding/escaping the value for security…

      If not, could you drop us an email via https://advancedcustomfields.com/support please? Mention my name in the subject and i’ll grab the ticket and we’ll work through this; very interested to know what’s happening!

      Cheers

      • Tiny Idea says:

        Sorry the error was on my end. I have a massive amount of fields, and there was two youtube embeds on the page. The one rendering i had already changed to get_field

  • Kevin says:

    Hi Liam, I wonder if there is anything you can do to improve the specificity of the change detector? I’ve seen a number of false positives due to use of the text alignment buttons in Tiny MCE editor – This injects a style="text-align: center;" attribute on the tag, but after it has been run through the wp_kses system the trailing semicolon is removed from the style declaration. (This is due to the fact that the CSS filter in the kses system only adds a semicolon BEFORE the NEXT css property, so the last one is never given a semicolon) https://github.com/WordPress/wordpress-develop/blob/6.4/src/wp-includes/kses.php#L2617

    • Liam says:

      Hey Kevin,

      Yeh, we’re aware of this being flagged. The problem is, the detection is tied to plugin releases, so we can’t quickly make changes to it. It’s also possible some developers would still want to know about a change like this – or they’re doing something in a style tag that’s actually invalid and will end up being removed; so trying to write a good all-round detection algorithm here that can know exactly what has changed is probably not viable.

      We also have to run this on every output of the_field, so we’re cautious about the performance implications building anything more than a very basic comparison would have.

      I’m hoping to add htmlentities encoding detection in ACF 6.2.6 so we can not flag that, but I think the TinyMCE "tidying" kses performs is likely to remain as a detected change.

      We’ve got a few other options released already as adhoc plugins which are much easier for us to update though, for example we have a plugin which will output the "before" and "after" values to the PHP error log to help with this: https://github.com/lgladdy/acf-escaping-debug-plugin

      • Kevin says:

        I understand the concern about performance implications, and I understand the difficulty parsing through the HTML in a way that handles all the messiness that browsers (and KSES) deal with. But I think there’s some low hanging fruit you can consider adding to 6.2.6 for style attributes. In the majority of cases where there is well-formed and cleanly formatted HTML with style attributes, I think this regex logic should be enough to confirm that there is a false-positive match on "changed content due to KSES":

        $kses_str = wp_kses_post($input_str);
        $likely_false_positives_str = wp_kses_normalize_entities($input_str);
        $likely_false_positives_str = preg_replace_callback('/s+style="([^"]*)"/', function($matches){
           $css = '';
           if ( empty( $matches[1] ) ) {
            //empty style attribute gets removed by wp_kses_post
            return '';
           }
            $css_rules = explode(';',$matches[1]);
            foreach($css_rules as $css_item) {
                $css_item = trim( $css_item );
                if ( '' === $css_item ) {
                    continue;
                }
                if ( '' !== $css ) {
                    $css .= ';';
                }
                $css .= $css_item;
            }
            return ' style="' . $css . '"';
        }, $likely_false_positives_str);
        if ( $likely_false_positives_str === $kses_str ) {
          $is_false_positive = true;
        }

        If you can’t incorporate the above into your 6.2.6 release, maybe you could at least incorporate some "Likely false positive" reporting in that escaping debug plugin ?

  • Otto Fischl says:

    Good morning, just to verify: I do not have to change my the_field- and the_sub_field-calls, unless they are retrieving e.g. iframes, scripts or any other non-regular-text. Is that correct? Thank you for your answer.

    • Liam says:

      Hey Otto,

      Exactly this. If you don’t use iframes or scripts (or a few even less likely options, like link tags used for stylesheets) you can just do nothing and allow our automatic escaping help keep you safe from XSS attacks.

      Thanks, Liam

  • Ilian Kumchev says:

    Hi in out site we got the message "ACF will soon escape unsafe HTML that is rendered by the_field(). We’ve detected the output of some of your fields will be modified by this change." for 4 ACF files we use and output in php files with the_field(). All this 4 fields are WYSIWYG fields The code to output one of the field looks like this <div class="mri-postcontentinnerwrapperitem"> <?php the_field(‘diagnosis_definition’); ?> </div>

    So should We change the code above like this: <div class="mri-postcontentinnerwrapperitem"> <?php echo acf_esc_html( get_field(‘diagnosis_definition’) ); ?> </div>

    or any other way?

    Thanks

  • Francesco Brancia says:

    Sorry but I would like to understand what exactly I should do. this what i see:

    ACF PRO — ACF now automatically escapes unsafe HTML when rendered by the ACF shortcode. We’ve detected the output of some of your fields will be modified by this change. Learn how to fix. Hide details

    booking_script_2 (booking_script_2) – rendered via acf_shortcode booking_script (booking_script) – rendered via acf_shortcode

    I created two WYSIWYG fields and inside I put this code: <booking-widget widget-id="fe25948a-858f-4a46-89f0-5b8091a5539d"></booking-widget><script type="text/ javascript" src="https://widgets.regiondo.net/booking/v1/booking-widget.min.js"></script>

    in the Elementor Pro template page, I inserted a shortcode field to recall the dynamic field [acf field='booking_script'] & [acf field='booking_script_2'] but I don’t see anything.

    Before the update everything worked. Can you explain to me what I have to do exactly? Thank you very much

    • Liam says:

      Hey Francesco,

      Because it’s insecure for us to render script tags in the shortcode, you need to explicitly say it’s allowed. You can do this with the following code:

      add_filter(
          'acf/shortcode/allow_unsafe_html',
          function ( $allowed, $atts ) {
              if ( $atts['field'] === 'booking_script_2' || $atts['field'] === "booking_script" ) {
                  return true;
              }
              return $allowed;
          },
          10,
          2
      );
  • Amina Hashimi says:

    On my site https://allekitools.com I have 3800 posts who all use 5 custom fields and ACF flags every field as unsafe and I have literally no idea what to do now. I dont understand at all how to fix this from this article. The fields have simple html for formating like <ul><li> I have embeded them via simple shortcode as wordpress text field. What do I need to do now? help is appreciated.

    • Liam says:

      Hey Ki,

      The notice isn’t warning you that anything is unsafe – just that some change will occur when ACF 6.2.7 is released. This is likely given you say you’ve got simple html, HTML encoding or tidying of markup from TinyMCE if they’re WYSIWYG fields.

      You likely do not need to do anything if you’re not using <iframe> or <script> tags in your fields. If you want to test you can use the filter listed in the post above to enable the new behaviour early to confirm it.

      • Amina Hashimi says:

        Thx for the quick reply. I have missinterpreted the message.

      • Ilian Kumchev says:

        Can I ask why my comment above this one is not approved yet and there is no reply on the question I asked for but there is reply of the next comments and questions after mine?

        • Liam says:

          Hey Ilian,

          Our replybox system for comments doesn’t show me unapproved comments and are approved by other folks, so I’m sorry I didn’t see it.

          As for when it decides something should be held for review – i have no idea! But it does seem to be when folks include code… but i’m not sure of the exact algorithm.

          You’re best off emailing us anyway, via https://advancedcustomfields.com/support – but i will reply to your original post now it’s been approved.

      • Ilian Kumchev says:

        As additional here is what i asked on my comment that is still not approved and without reply: "Hi in out site we got the message "ACF will soon escape unsafe HTML that is rendered by the_field(). We’ve detected the output of some of your fields will be modified by this change." for 4 ACF filelds we use and output in php files with the_field(). All this 4 fields are WYSIWYG fields The code to output one of the field looks like this <div class="mri-postcontentinnerwrapperitem"> <?php the_field(‘diagnosis_definition’); ?> </div>

        So should We change the code above like this: <div class="mri-postcontentinnerwrapperitem"> <?php echo acf_esc_html( get_field(‘diagnosis_definition’) ); ?> </div>

        or any other way?

        Thanks"

        • Liam says:

          Hey Ilian,

          If your fields don’t contain iframe or script tags, you can ignore the warnings and you’ll be covered automatically. That said, if you do want to clear the warnings early (I get it!) then you can swap to the code you provided. Your suggested change there is perfect. Thanks!

  • Manuel Neumair says:

    Does ACF also scan the child themes for the_field & the_sub_field and display warnings in the admin area?

    • Liam says:

      There is no kind of scanning going on – we just log when the_field is actually used on the front-end at runtime. So, it’s only checking what code is actually being rendered to the front-end.

  • Johan Carlsson says:

    Cant really get a grip of this…

    I usually assign the value to a variable like $title = get_field(‘title’); Then I use echo to output it. That seems to trigger no warnings?

    But if i just do <?php the_field(‘title’);?> there is warnings. So do I have to replace all those with <?php echo wp_kses_post(get_field(‘title’));?> instead?

    Also, there seems to be warning om some fields but now all. I have loads of WYSIWYG-fields outputed with <?php the_field(‘content);?> that doesnt trigger anything?

    Need to be clearer what to change?

    • Liam says:

      Hey Johan,

      When you use $title = get_field('title'); you’re saying you want the raw unescaped value. If you echo that, you’re allowing unescaped content to be output. This will not generate warnings because you’re not using the_field.

      That said, you should be escaping your output by default. It’s important to help prevent XSS attacks, so instead of echo $title after you’ve assigned it a variable, i’d use echo esc_html($title) to remove any HTML. This is general good practice for web dev though.

      Your WYSIWYG fields might be fine – you only need to swap from the_field if you want to output <iframe> or <script> tags.

      • Johan Carlsson says:

        I get that its important but cant really go back and fix this an all sites that ive done in the last 5 years xD…

        "Your WYSIWYG fields might be fine"? If not you need to update the docs on the website beacuse you dont mention anything about a change needed there.

        So, no more use of the_field (except on WYSIWYG-fields) and all other outputs should be used like <?php echo esc_html(get_field(‘field_name’));?> ? Is that correct?

        Thanks for the reply but you guys really need to make it more clear that to change…

        • Liam says:

          Hey Johan,

          Unfortunately, there isn’t really an easy way to distill the way forward because it varies depending on how your fields are used and what data you’re storing in a field.

          It all comes down to the iframes or scripts question. If you’re using them, you need to make changes, if not, you’re likely fine – and the warnings are likely to do with HTML encoding – things like & being output to their html entity (&) equivalent. It’s not a breaking change, but it is a change we need to alert you about in case it does matter.

          It’s likely to matter if you’re doing anything particularly specialist, such as outputting a field value directly into the middle of an inline JavaScript function or something where you’ll need to be more considered about what encoding your code will support.

          Because there are so many users using ACF in so many different ways, it’s not possible to give a "just do this" answer – but we think we’ve covered off every possibility in the blog post above.

          • Johan Carlsson says:

            Thanks, and I get it. But would be good to get an answear of this question:

            So, no more use of the_field (except on WYSIWYG-fields) and all other outputs should be used like <?php echo esc_html(get_field(‘field_name’));?> ? Is that correct?

        • Liam says:

          Hey Johan,

          Sorry – we’ve hit the depth limit for comment replies, so i have to reply to your latest one here, regarding no more use of the_field.

          You’re absolutely welcome to keep using the_field, and for the majority of fields and outputs it’s absolutely fine, and you’ll get the escaping included as part of using it.

          The only time you need to swap is if you want to handle escaping yourself. So, that’s if you need to output something like iframes or scripts inside a field, or you want some specialist escaping rather than our "catchall" wp_kses_post. The full list of escaping functions in WordPress is here: https://developer.wordpress.org/apis/security/escaping/

          • Johan Carlsson says:

            Oh okej… I never output scripts or iframes thru ACF-fields… possibly that clients may put iframes in the WYSIWYG, but thats it.

            I have still seen loads of warnings tho, but mabye thats beacuse of & and so on.

            I just need to know if I always have to esc_html every single ACF-field I want to echo or if its just when there is scripts or iframes used.

            Sorry for my inconvinience, love ACF haha

        • Liam says:

          Hey again Johan,

          Yeh, I understand. Anything you echo get_field, you should be escaping it where you can – just like you escape any other thing from WordPress. This isn’t ACF specific, rather just important security practice when building anything on the web.

          The WordPress documentation explain this well: https://developer.wordpress.org/apis/security/escaping/#toc_3

          Specifically, that documentation includes a "except when you can’t" section, and that’s essentially what we’re doing here with things like iframes and scripts. the_field will basically start using those WordPress standards of escaping by default, and we encourage all users to do the same when using get_field.

  • Thomas Frost says:

    Hello,

    We’ve recently received the dialog message for this update on one of our client’s websites. We’ve read through the changelog information above, and want to be certain we are prepared for the February roll out.

    I currently receive the following:

    • alert_3_title (alert_3_title) – rendered via the_field • main_content (main_content) – rendered via the_field • insights_type (insights_type) – rendered via the_field • remote_url (remote_url) – rendered via the_field • short_summary (short_summary) – rendered via the_field • section _title (sections_2_section_title) – rendered via the_sub_field • award_title (sections_1_awards_7 _award_title) – rendered via the _sub_field • content (sections_0_content) – rendered via the_sub_field • video_embed_code (sections_2_videos_0_video_embed_code) – rendered via the_sub_field • endorser (testimonials_O_endorser) – rendered via the_sub_field • testimonial (testimonials_1_testimonial) – rendered via the_sub_field • subtitle (subtitle) – rendered via the_field

    We also have a mirrored staging site that is near identical. We did update to the latest version and receive a shorter list:

    • insights_type (insights_type) – rendered via the_field • remote_url (remote_url) – rendered via the_field • short_summary (short_summary) – rendered via the_field • alert_3_title (alert_3_title) – rendered via the_field • main_content (main_content) – rendered via the_field

    Will we see changes from the update? Having read the above article, we are unsure if these are actionable changes that we need to make on our end, or if these are HTML shortcodes that will be automatically "converted" in the update next month?

    Thank you-

    • Liam says:

      Hey Thomas,

      We only log when we think things will change when you view a page on the frontend of the site, so that’s why you’re seeing seperate. Looking at your field groups there, i’d imagine the video_embed_code fields will need to swap to echo get_field (or echo get_sub_field)

  • Simon says:

    I’m using ACF on an hundred sites ans some times I use a WYSIWYG field to push iframe. On my php template I use the_field or the_sub_field to display the content of my field. What I have to do for let my website works as now ?

    • Liam says:

      Hey Simon,

      If your WYSIWYG fields contain iframes, you’d need to swap them to echo get_field('field_name') or echo get_sub_field('sub_field_name') otherwise their content will be escaped. This is a good thing for anything which doesn’t contain an iframe.

      Alternatively, you can use the sample code in the article to say any ACF field is allowed to contain an iframe.

      • Simon says:

        Thanks for your feedback, which code is it for this part :

        Alternatively, you can use the sample code in the article to say any ACF field is allowed to contain an iframe.

        Thanks

        • Liam says:

          Hey Simon,

          add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_iframe_tag', 10, 2 );
          function acf_add_allowed_iframe_tag( $tags, $context ) {
              if ( $context === 'acf' ) {
                  $tags['iframe'] = array(
                      'src'             => true,
                      'height'          => true,
                      'width'           => true,
                      'frameborder'     => true,
                      'allowfullscreen' => true,
                  );
              }
          
              return $tags;
          }
  • Matt Arnzen says:

    Simple question, where in wordpress do I make these edits like:

    apply_filters( ‘acf/the_field/allow_unsafe_html’, false, $selector, $post_id, $field_type, $field_object )

    • Liam says:

      Hey Matt,

      Your theme’s functions.php is a good place if it’s a custom theme, otherwise, you’d need to add it in a custom plugin to handle things for you.

  • brent20 says:

    Hello,

    I’m a little late to the party here, but I run websites where we use the_sub_field() and the_field() quite often for WYSIWYG content which typically consists of Vimeo embeds and Square/Aquity booking widgets, so I have a few questions:

    1. If I simply disable the ACF shortcode on each of my sites, will I have to do anything else and will my scheduling embeds and videos function as normal with the upgrade?

    2. If not, question: Here’s a pretty standard way I call a field:

    <?php if(get_field(‘wysiwyg’)) { ?> <?php the_field(‘wysiwyg’); ?> <?php } ?>

    I tried this to get a WYSIWYG containing multiple Vimeo embeds using this code: <?php if(get_field(‘wysiwyg’)) { ?> <?php echo acf_esc_html( get_field(‘wysiwyg’) ); ?> <?php } ?>

    • nothing shows up by doing this

    I also tried this to call the field: <?php echo esc_attr( get_field( ‘wysiwyg’ ) ); ?>

    • it renders renders embeds as html text

    Finally, I tried this: <?php if(get_field(‘wysiwyg’)) { ?> <?php echo get_field( ‘wysiwyg’ ); ?> <?php } ?>

    • and it works correctly pulling the content properly.

    So I guess my question: is this way of calling a wysiwyg field the right way to grab video and scheduling embeds with the new update and therefore, I will need to update all wysiwyg embed field code on all sites to reflect “echo get_field(‘fieldname’)” or is there an additional step?

    If I did do this correctly, I still am seeing the notice “wysiwyg (wysiwyg) – rendered via the_field” on the site backend after I made this update – should notices go away on their own after the proper "the_field();" calls are updated?

    Thanks in advance.

    • Liam says:

      Hey Brent,

      Your final code sample there will output the WYSIWYG without any escaping, which is why it’s working – but it will allow any HTML, including <scripts> (which, you probably need for the booking widget anyway).

      iframes are likely safer, and likely all the Vimeo embed uses? So, you could decide to say ACF fields are allowed to contain iframes anywhere with the following code:

      add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_iframe_tag', 10, 2 );
      function acf_add_allowed_iframe_tag( $tags, $context ) {
          if ( $context === 'acf' ) {
              $tags['iframe'] = array(
                  'src'             => true,
                  'height'          => true,
                  'width'           => true,
                  'frameborder'     => true,
                  'allowfullscreen' => true,
              );
          }
      
          return $tags;
      }

      You’d still need to swap to echo get_field('embed_field_with_scripts'); for a field with <script> tags – but the others will be protected.

      Thanks!

      • brent20 says:

        Thanks. To be clear, I should add the "add_filter" code exactly as you have it above to functions.php on all of my sites? Then I need to update "get_field(‘field_name’);" to "echo get_field(‘field_name’);" everywhere a wysiwyg field with an iframe embed is on all of my sites as well?

  • martinkariuki7 says:

    Important but drastic, the rollback plugin is about to be downloaded a million times :))

  • Hein Htet Thu says:

    I’m not a WordPress developer but a friend of mine asked me to take a look at his website (https://www.sampantravel.com/sleeping/) because of the styling issue. And I found out that the plugin ACF Repeater is acting crazy by not showing 3 cards in one row but instead only showing one card per row. I think the issue has to do with this security release. Here’s the chunk of code that’s causing error.

    <section id="grid" data-aos="fade-up" data-aos-duration="2000"> <div class="container-fluid"> <div class="row"> <?php echo do_shortcode(‘[ajax_load_more_filters id="sleepingfilters" target="sleepingfilters"]’); ?> <?php if(is_category()){ $cat = get_query_var(‘cat’); $category = get_category ($cat); echo do_shortcode(‘[ajax_load_more filters="true" target="filters" category="’.$category->slug.’" container_type="div" id="sleepingfilters" post_type="post" posts_per_page="6" images_loaded="true" max_pages="100" cache="true" cache_id="cache-‘.$category->slug.’"]’); } ?> </div> </div> </section>

    Can someone take a look pls and kindly let me know how I can solve this?

    Many thanks.

  • Owen says:

    One of our sites had the notification info banner show up, so we added the debug code to see what was causing it. The error log output picks up a couple of posts that use wysiwyg fields in a repeater, they have simple <a href… tags that link to pdf files, why would these be affected?

  • Mikeq Dreiling says:

    Thanks Liam. We use several types of embeds (HubSpot, Wistia, Ceros). Our page.php is fairly simple and ACF shows the warning banner at the top of the plugin page. content (content_wraps_6_content_blocks_0_content) – rendered via the_sub_field.

    Our page.php page only uses the_sub_field in one spot. Is it as simple as changing to echo the_sub_field('content');?

    I’ve done that and the warning is still present. Will it always be present? Thank you!

    • Liam says:

      Hey Mike,

      Yup, that sounds like a plan! If you clear the warning, it shouldn’t come back. Clearing the warning clears the log, so will only come back if we’ve still detected something will change.

  • Hein Htet Thu says:

    I’m not a WordPress developer but a friend of mine asked me to take a look at his website because of the styling issue. And I found out that the plugin ACF Repeater is acting crazy by not showing 3 cards in one row but instead only showing one card per row. I think the issue has to do with this security release. Here’s the chunk of code that’s causing error.

    <section id="grid" data-aos="fade-up" data-aos-duration="2000"> <div class="container-fluid"> <div class="row"> <?php echo do_shortcode(‘[ajax_load_more_filters id="sleepingfilters" target="sleepingfilters"]’); ?> <?php if(is_category()){ $cat = get_query_var(‘cat’); $category = get_category ($cat); echo do_shortcode(‘[ajax_load_more filters="true" target="filters" category="’.$category->slug.’" container_type="div" id="sleepingfilters" post_type="post" posts_per_page="6" images_loaded="true" max_pages="100" cache="true" cache_id="cache-‘.$category->slug.’"]’); } ?> </div> </div> </section>

    Can someone take a look pls and kindly let me know how I can solve this?

    Many thanks.

  • jamesrvine says:

    Hi, I have two code snippets I use reguarly. Could you let me know how to update these to the current echo code please?

    <?php if( get_field('role') ): ?>

    <div class="role"><?php the_field(‘role’); ?></div> <?php endif; ?>

    and

    Is this, which features an "echo", all good?

        <?php echo do_shortcode(get_field('slideshow')); ?>

    Thanks so much!

    • Liam says:

      Hey Jim,

      I suspect your code there doesn’t need any changes! Assuming role does not contain an iframe or script in it’s value?

      • jamesrvine says:

        Thanks Liam! It may show a script in the future. The "slideshow" one above definitely loads a script.

        One further question if that’s OK, but what happens if it tries to load a iframe or script? Does it simply not load or does it take down the page/entire site?

        • Liam says:

          The unsafe tags are stripped… so if you’ve got <iframe src="bla"></iframe> it just wouldn’t be shown at all.

          If you’ve got something like <script>console.log('test');</script> the script would be removed, meaning console.log('test') would be output to the screen.

  • Shay W says:

    Very long and convoluted explanation. How about just a basic – this is what is being updated. This is what you change it with. None of my fields using the_sub_field() are outputting HTML but I am sick of seeing the notice so I changed it, as you suggested, to get_field() which doesn’t work.

    • Liam says:

      The top paragraph of the article is the "TL:DR;" but unfortunately, this is a complicated topic and it needs detailed explanation of all the options and ways forward.

      The notice only appears when the log has entries. If you’ve dismissed the notice, which clears the log, and it comes back – you still have instances of the_field or the_sub_field.

  • Asyhar Anas says:

    My solution, I create my own shortcode. Let say "acf2" or something

    add_shortcode( ‘acf2’, ‘f_acf2’ ); function f_acf2($atts) { $myField = $atts[‘field’]; $myReturn = get_field($myField); return $myReturn; }

    So, I can use [acf2 field="field_name"]

    Is this safe for security?

    • Liam says:

      Hey Asyhar,

      Nope, this won’t be safe. You’re passing any field raw out to the browser, regardless of it’s contents. The point of this change is to introduce escaping, which is important for anytime any web app outputs user content to the browser.

  • Evan Bedell says:

    If the alert notice is cleared in staging and doesn’t return, does that mean the issue(s) are all fixed?

    • Evan Bedell says:

      I’ve cleared/ X’d out of the notice before without making changes, and it has never returned. So wondering how you can tell if the issue(s) are actually fixed?

      • Liam says:

        Hey Evan,

        The notice would return if you were still affected.

        • Evan Bedell says:

          Why would this notice first appear, then, if I didn’t make any changes and closed it and it never returned? Wouldn’t that mean I was never actually affected in the first place?

          • Liam says:

            It could be the field value has been updated in ACF and is no longer changed, or it could be nobody has visited the page of your site which contains the affected field values.

  • Gerald Thulbourn says:

    I’m sorry but do you realise the number of old sites that you will break with your approach? Yes I understand the security aspect but you seem to be taking a very narrow view of this. Couldn’t you just have had a warning about this and allow people to OPT IN if the site was under active development? What about all those sites that are NOT under active development but are set to auto-update? Are you going to punish them for having auto-update set to try to stay secure? And maybe your documentation for time poor (read "doing this for free to try to protect old websites for past customers so they don’t just go pop") web developers could have been a little more succinct? You say the issue is with users of contributor level or higher. In the great big world outside there is a thing called WooCommerce – how does the "customer" user level feature in this? I’d imagine not a problem as they have no rights to publish, but your note on this doesn’t mention that (remember time poor – doing for free). I know you are trying to protect people so your hearts are true – but it doesn’t seem that you have taken paid attention to the huge number of sites that are not in active development being potentially broken by this change.

    • Liam says:

      Hey Gerald,

      We do understand that a significant amount of sites may need be to checked or updated here, but we really don’t have any choice. We, just like WordPress core when they fixed a shortcode vulnerability in WP 6.2.1 which broke websites, have to patch by default for this kind of thing where there is no other option to patch security vulnerabilities.

      Those same old, unmaintained websites are exactly the ones more likely to be vulnerable to other security risks which make this kind of fix even more important.

      Customers in woocommerce are not a contributor or higher level user, and have no permissions to create or edit posts, so are not affected by this at this time.

  • Marko Stančić says:

    I followed the guide but I still have notice that said:

    ACF PRO — ACF will soon escape unsafe HTML rendered by the_field(). We’ve detected that this change will modify some of your fields’ output. Learn how to fix it. Hide details

    item (book_list_0_item) – rendered via the_sub_field maybe_you_text (maybe_you_text) – rendered via the_field

    and if I try to search the whole project for "the_field" or "the_sub_field" the Search will not find anything.

    I followed the guide but I still have notice that said:

    ACF PRO — ACF will soon escape unsafe HTML rendered by the_field(). We’ve detected that this change will modify some of your fields’ output. Learn how to fix it. Hide details

    item (book_list_0_item) – rendered via the_sub_field maybe_you_text (maybe_you_text) – rendered via the_field

    and if I try to search the whole project for "the_field" or "the_sub_field" the Search will not find anything.

    This is the way how i print field: <?php echo get_field( ‘maybe_you_text’, ‘option’ ); ?>

  • Rahul Wani says:

    I currently facing similar issue with ACF functions get_sub_field & the_sub_field. I have more than 100 websites build using ACF and each website has almost 30 slices. Please find example below. Let me what exactly I have to do remove those warnings from dashboard as well as We should not get any error in future once V 6.2.7 releases. Though each website isn’t using all slice templates i.e. I’m getting warning for some of separate files only on each website. Example of one of slice template. Can you please check and let me know how exactly I have to remove / make it compatible to get this piece of code working in current and future ACF Pro versions.

    <?php $video_slice_thumbnail = get_sub_field(‘video_thumbnail’); ?> <section class="video_slice clearfix"> <div class="content"> <div class="left"> <?php the_sub_field(‘video_text’); ?> </div><!–left–> <div class="right"> <?php $video_overlay_shortcode = ”;

            if ( get_sub_field('video_host') == 'YouTube' ) {
                echo '<a class="no play_icon" href="https://www.youtube.com/watch?v='.get_sub_field('video_id').'"></a>';
                echo '<a class="no video_lightbox_anchor_image" href="https://www.youtube.com/watch?v='.get_sub_field('video_id').'" title=""><img src="'.$video_slice_thumbnail['url'].'" alt=""></a>';
            }//if video_host
            else {
                echo '<a rel="wp-video-lightbox" href="https://www.vimeo.com/'.get_sub_field('video_id').'?width=640&amp;height=480" class="play_icon"></a>';*/
                echo '<a class="no play_icon" href="https://vimeo.com/'.get_sub_field('video_id').'"></a>';
                echo '<a class="no video_lightbox_anchor_image" href="https://vimeo.com/'.get_sub_field('video_id').'" title=""><img src="'.$video_slice_thumbnail['url'].'" alt=""></a>';
            }//else not youtube
            //echo do_shortcode($video_overlay_shortcode);
        ?>
    </div><!--right-->

    </div><!–content–> </section><!–video_slice–>

  • John Saputo says:

    Will echo get_sub_field(); work instead?

    • Liam says:

      Hey John,

      It will – but you need to understand that doing that you’ll be sending user input raw to the client. This is fine if you keep your site secure and up to date and trust all your users, but it’s much safer to only allow expected HTML in there if there’s any risk that a malicious user could either update the field’s value to something unsafe.

      Thanks!

      • John Saputo says:

        Is there a way for shortcode to be able to work when using wp_kses_post()?

        I am using the_field() for a WYSIWYG field, and it’s used to display shortcode on a few pages of the site

        • Liam says:

          Hey John,

          Are you having issues with them? In theory, the WYSIWYG field should still be working for you; we do a different kind of escaping on the WYSIWYG field – it’s escaped before shortcodes are processed, so any shortcodes should still work. If you’re having issues, drop us an email at https://advancedcustomfields.com/support with the full contents of one of your WYSIWYG fields and we’ll test!

  • Tina says:

    I’m having an issue with a Gravity Forms shortcode inside of an ACF field. WP KSES strips out some important HTML comments inside of a script tag at the bottom of the form. All of the form submission logic is in this script. I have allowed the script tag through wp_kses_allowed_html but I cannot figure out how to get the HTML comments to stay put so they don’t mess up the rest of the code block when stripped out. The line begins with an open comment tag (/) and then has some legacy HTML comment code <![CDATA[ / that gets stripped out, leaving just the open comment tag, effectively commenting out a big block of JS until it hits another end comment tag. How do I get around this limitation of wp_kses to leave in the HTML comment code?

    • Liam says:

      You won’t be able to use wp_kses for this. If you use a WYSIWYG field, we’ll allow any HTML a shortcode generates by default, if you’re using another field type you’ll need to modify whatever code you’ve got to process the shortcode.

  • ankevanreeth says:

    Thank you for keeping security a priority! I have a question, as I’m not sure I understood the update correctly. I am mainly using ACF in the following way:

    <?php $icon_vacatures_link = get_sub_field( 'icon_vacatures_link' ); ?>
      <?php if ( $icon_vacatures_link ) : ?>
        <img src="<?php echo esc_url( $icon_vacatures_link['url'] ); ?>" alt="<?php echo esc_attr( $icon_vacatures_link['alt'] ); ?>" />
      <?php endif; ?>
    And / or
    <?php if( get_sub_field('title_vacatures_link') ): ?>
      <h5><?php the_sub_field( 'title_vacatures_link' ); ?></h5>
    <?php endif; ?>

    How would I update this? Also, I have + 50 sites that would need to be updated. Will all those sites break if I don’t change the code?

    • Liam says:

      I don’t think you’ll need to update anything here! Those fields should not contain iframes or scripts or other potentially unsafe HTML and will carry on working.

  • P H says:

    Sorry but I didn’t understand everything. I am using ACF to insert youtube video via iframe. So It didn’t work anymore. I didn’t understood how to use add_filter( ‘acf/the_field/escape_html_optin’, ‘__return_true’ ); ? In functions.php, just like that, it didn’t change anything… Thank you in advance for any help.

  • Sijmen Kingsbergen says:

    I have opened a ticket for this. Could you please respond? I need to keep my forms (sign up) working.

  • Mike Batcheller says:

    Added the filter and then received a warning about another field. Warning message: section_text (ll_sections_13_section_text) – rendered via the_sub_field

    my code – <code>add_filter( ‘acf/the_field/allow_unsafe_html’, function( $allowed, $selector ) { if ( $selector === "ll_sections_11_section_text" || $selector === "ll_sections_13_section_text" ) { return true; } return $allowed; }, 10, 2); </code>

    Cleared the warning message and then refreshed page. Still get message on field ‘ll_sections_13_section_text’

  • Will Hall says:

    1) What should I do in the case of "yes i want unsafe html to be escaped, please stop showing the error message to everyone who uses wp-admin"? 2) It appears that the behavior of <?php the_sub_field is now different from <?= get_sub_field. The former now removes unsafe html, while the latter does not. Shouldn’t this behavior be called out on their respective documentation pages? the_field’s page literally says "Please note this function is the same as echo get_field()". https://www.advancedcustomfields.com/resources/get_field/ https://www.advancedcustomfields.com/resources/the_field/ 3) Considering that the_field is being modified to remove unsafe html, why is an equivalent change to get_field not also being made? Is it because get_field is assumed to be used by developers who know what they’re doing? That makes sense, though I’m not sure the documentation or naming scheme calls out this crucial (and new) difference. get_field is innocuous looking but is actually very unsafe (always has been). Whereas the_field is (now) dramatically more safe, but looks identical.

    • Liam says:

      Hey Will,

      1. We’ve shown the filter in the blog post above for how to disable the notification.
      2. We’ve not updated the documentation yet, because the update isn’t live – we will along with ACF 6.2.7’s release.
      3. get_field has a new fourth parameter, as mentioned in the blog post and it’s documentation, which allows you get the escaped version of a field if you wish – but most developers will likely want to handle the escaping themselves.
  • Ali Raza says:

    Should I replace get_field(‘field_name’) with wp_kses_post( get_field(‘field_name’) )

    Everywhere in my files? OR is there any way where inside "function.php" it updates everywhere?

    Secondly, should I also do this for get_sub_field?

    Lastly, If I don’t do anything, despite ignoring the vulnerability. Will this still works? or will be break my side in future ACF updates?

    • Liam says:

      Hey Ali,

      You should use an appropriate escaping function, based on the content contained inside of it. wp_kses_post is a pretty good starting point. But, if you’re using just a url or something that shouldn’t contain HTML at all, you can use esc_url or esc_html which will be considerably more performant. You can find more details here. https://developer.wordpress.org/apis/security/escaping/

      Yes, you should do this for get_sub_field too. Anytime you output any user-entered content on a web application you should make sure it is escaped as necessary.

      If you do nothing, if you’re using get_field, nothing will change for you. if you’re using the_field, we’ll automatically escape things for you.

      We’re extremely unlikely to ever change get_field, so we don’t expect anything to change if you do nothing, and are only using get_field – albeit accepting the security risk if you’re not escaping.

  • Evan Bedell says:

    Would I need need to update all of these "the_field" to "get_field", if that is what is giving me an error alert?

    <?php if(get_field(‘google_tag_header_code’, ‘option’)) the_field(‘google_tag_header_code’, ‘option’); ?> <?php if(get_field(‘crazy_egg_analytics_code’, ‘option’)) the_field(‘crazy_egg_analytics_code’, ‘option’); ?> <?php if(get_field(‘google_analytics_code’, ‘option’)) the_field(‘google_analytics_code’, ‘option’); ?> <?php wp_head(); ?> </head> <body <?php body_class(); ?>> <?php if(get_field(‘google_tag_body_code’, ‘option’)) the_field(‘google_tag_body_code’, ‘option’); ?>

    • Liam says:

      Hey Evan,

      Sorry, it’s hard to read the code here with the formatting on the comments, so it could be i’m missing context here, but using the_field to output google tag body code is likely to break come 6.2.7.

      You’ve change some instances to get_field (in your if statements) but you haven’t changed the actual output to be "echo get_field" – which you’ll need to do as well.

  • Sam Insalaco says:

    If I am reading the comments correctly, if we are using a shortcode within a WYSIWYG editor (DIVI) to output the value of fields (mostly just text) from ACF, we should be fine? Am I understanding this correctly? He have a LOT of sites where we are doing this, so we would need to know if we need to go back into all of them and make changes to how we pull in these values. Thank you.

  • Sascha Gernhardt says:

    Hi Liam, I just changed the_field and the_sub_field on all occasions to wp_kses_post(get_field(”)); However, in the WordPress Backend, ACF still shows me one occasion, where the_field is being used. Is this some sort of caching issue? There is definitely no the_field left in our code.

    • Liam says:

      Hey Sascha, did you clear the notification? That’s what resets the logs… it shouldn’t cache, but it’s viable if something is weird going on with memcache on your host where our log value isn’t cleared properly.

      • Sascha Gernhardt says:

        I did not, but it seems that all the other fields out have been stripped out, except for this one. But yeah, I will try to clear the notification. Thanks

  • Peter Zwickl says:

    What can I do to prevent the modification of the enlisted items?

    ACF PRO — ACF will soon escape unsafe HTML that is rendered by the_field(). We’ve detected the output of some of your fields will be modified by this change, but this may not be a breaking change. Learn more. Hide details.

    schwerpunktthema_text () – rendered via the_field accordion_content (accordion_1_accordion_content) – rendered via the_sub_field slider_headline (slider_0_slider_headline) – rendered via the_sub_field intro_text (intro_text) – rendered via the_field accordion_headline (accordion_1_accordion_headline) – rendered via the_sub_field news_text (news_text) – rendered via the_field reiter_content (reiter_5_reiter_content) – rendered via the_sub_field slider_subline (slider_0_slider_subline) – rendered via the_sub_field

    • Liam says:

      Hey Peter,

      The modification is likely okay – it will be correctly encoding user input for output, things like & will become &amp; which is actually a good thing.

      The only time this will be an issue is if your accordion content contains any custom embedded iframes or scripts, which is probably unlikely.

      Have you upgraded to ACF 6.2.7 already? If so, and the accordion is still displaying correctly, you’re all good and don’t need to change anything.

      • Peter Zwickl says:

        Hi Liam, I have upgraded to ACF 6.2.7. But as before, I can’t access the "Headline", "Subline", "Linktext" and "Link" of the Slider, irrespective of existing or new sites. Where exactly can I add what to fix this? I hope you can help us! Thanks in advance Peter

        • Liam says:

          Hey Peter,

          We’d recommend contacting your site/slider developer in this case I think, there isn’t any reason why this change should have impacted those fields as they almost certainly won’t contain HTML.

          You can contact our support team too if you’d like us to take a closer look too, but the developers of the slider will likely know where to look faster. https://advancedcustomfields.com/support

  • Eoin says:

    Hi. A developer helped with the setting up our our site in the first instance and we now manage any updates. The developer used ACF Pro and I have no idea how it works :(. The instructions on this page go way over my head as well. The plug in has updated to v6.2.5 automatically before I had the chance to make any changes. I get the following warning on the dashboard:

    ACF PRO — ACF will soon escape unsafe HTML that is rendered by the_field(). We’ve detected the output of some of your fields will be modified by this change. Learn how to fix. Hide details

    title (section_2_accordion_item_5_title) – rendered via the_sub_field intro (intro) – rendered via the_field

    I have no idea how to fix this or if the site is now vulnerable. Would someone be able to provide some step by step instructions? That would be much appreciated!

    • Liam says:

      Hey Eoin,

      You can upgrade to ACF 6.2.7 now and see. I wouldn’t expect that field to contain an iframe or script, so you will likely be able to upgrade without any issue.

      Thanks, Liam

      • Eoin says:

        Thanks for getting back to me Liam. I’ve updated to 6.2.7 and I don’t see the ACF Pro warning message any more. The site seems to be working ok. Am I safe to assume that the site is now safe and the vulnerability is resolved?

  • Steve Herman says:

    I have these errors below using ACF PRO, I am not a developer need some guidance to resolve these error step y step. I need to know in which file O need to make the changes and what changes.

    text (Text) – rendered via the_sub_field text (Text) – rendered via the_sub_field text_2 (Text) – rendered via the_sub_field text (Text) – rendered via the_sub_field feature (Feature) – rendered via the_sub_field welcome (Welcome message) – rendered via the_field header_code (Header Code) – rendered via the_field embed_code (Google Map Embed Code) – rendered via the_sub_field

  • Joe CSSI says:

    HI – I’ve spent the past day reading through these materials and trying to figure out how to get my iframe youtube video to work again on my site. My former site designer used ACF to give me a field where I put in the youtube iframe code, and in the php it uses: the_sub_field( ’embed_code’ ); which now doesn’t work with your update. Specifically what do I need to do so that I can make the video show up again? I’ve read through the article and all the comments and I can’t figure out how to solve this?

  • Main says:

    What do I have to change on this code?

    <div class="book-data">
        <p class="book-original-name"> <?php the_field('original_title'); ?></p>                   
        <p><?php the_field('date'); ?>, <?php the_field('place'); ?></p>
        <p><?php the_field('subgenre'); ?></p>
    </div>
    • Liam says:

      Probably nothing! I doubt any of those fields (based on their names) contain anything like script or iframe, so you’re safe to let the escaping run.

      • Main says:

        Thanks but I have a notice regarding ‘the_field(‘original_title’)’.

        • Liam says:

          The notice is just a heads up to check. If everything is fine, you don’t need to do anything, and in our next major release the notice will disappear.

          You can turn it off early if you like with the following code:

          add_filter(
                  'acf/admin/prevent_escaped_html_notice',
                  '__return_true'
              );
  • Dani O says:

    I have a field with the following HTML: <a href="javascript:toggleDrFlexAppointments(drFlexData);" class="termin testing headertermin">Online Termin vereinbaren</a>

    But in the frontend the ‘javascript:’ disappears. What do I have to insert into my functions.php to allow it, so it doesn’t destroy my link?

  • kushal palvai says:

    I’m using ACF pro 6.2.7 for my website, after i’ve updated to this version the gpa calculator on my website doesn’t seem to work — the function which i’ve used within the script is running outside and is visible on the screen of the page, the function was working alright before but after i’ve updated to 6.2.7 it stopped working, what should i do to make the script function start working again ? Should i change anything inside the template file for the short code ?

    • Liam says:

      Hey Kushal,

      Please contact our support team for help with this.

      • kushal palvai says:

        Hi Liam, I did infact raise a ticket but haven’t got anything back from them yet, as this is a very crucial issue, I’d appreciate if this gets resolved rather quickly. (Request #7121932)

    • kushal palvai says:

      description (Description) – rendered via the_sub_field — this is what i can see on my WP dashboard

      • Liam says:

        You’ll likely need to find the_sub_field('description') and change it to echo get_sub_field('description') if it’s the description file which contains the code.

        • kushal palvai says:

          I’ve tried implementing the above in the template file of acf pro but the entire website didn’t load up after this.

          • Liam says:

            Unfortunately, it’s not going to be possible to go any deeper on this here. Our support team will get back to you soon.

            If your original theme developer is available, they should be help you better than we can, as they’ll know the full details of how this was developed.

        • kushal palvai says:

          I’ve fixed the issue, by implementing the above changes inside the theme settings, thanks for your quick reply Liam.

  • Rima Gerhard says:

    Hi there. Will errors/warning only be reported in wp-admin when the page with the issue (an [acf field or the_field with the issue) is visited by a user?

    • Liam says:

      Hey Rima,

      Yup – we only log things as we encounter them to make sure we don’t report things which will be unaffected.

      • Rima Gerhard says:

        That is what I thought. It’s a bit impossible for me to manually visit each page on my site. I used Integrity Scan to hit all pages. Would such a scan trigger the errors? Or how do you suggest I test all pages on my site? There are > 20k.

        • Liam says:

          Hey Rima,

          You shouldn’t need to test each page, rather you need to consider each field type. Are any fields designed to contain HTML scripts or iframe tags? This is only likely to be things like if you’ve got an option field for google tag manager code or you’ve got a page with a field which contains a embedded podcast player widget.

          If you don’t expect your fields to contain scripts or iframes, you can allow the escaping to do it’s job and keep things escaped.

          If you do want to validate that, you could run an SQL query to check for any wp_postmeta meta_value‘s which contain <iframe, <script or <svg to see if there are any meta values for it.

          • Rima Gerhard says:

            Yes, that’s what I am doing now in the Database. I’m using this to see if there are any field values that have any such content. SELECT wp_posts.ID AS pid, wp_posts.post_title, wp_posts.post_type, wp_posts.post_status, wp_posts.guid, wp_postmeta.* FROM wp_postmeta INNER JOIN wp_posts ON wp_postmeta.post_id = wp_posts.ID WHERE wp_postmeta.meta_value LIKE ‘%<iframe%’ OR wp_postmeta.meta_value LIKE ‘%<script%’ OR wp_postmeta.meta_value LIKE ‘%<svg%’;

          • Rima Gerhard says:

            Also, Liam. We are using get_field instead of the_field to output. Is get_field affected by the Security release?

  • IQMH says:

    What if I want to disable this globally?

  • Moxie Services says:

    So just to clarify, I am using the shortcode [acf field="youtube_link"] in a wordpress editor. What should I use instead?

  • Matt Leaning says:

    Hi, is there anyway to get the ID’s of posts/pages that contain an ACF field which is escaping unsafe HTML? Thanks

    • Liam says:

      Hey Matt,

      You can install the debug plugin mentioned in the article above which will give you the page currently being loaded in your error logs.

      Alternatively, you could do a SQL query on wp_postmeta for any meta_value containing ‘<script’, ‘<iframe’, ‘<style’, ‘<svg’ for example.

  • Phil Vaive says:

    Hi there, this is really getting frustrating. I do not have any html in any of my ACF fields other than some basic heading tags, and I still see the error that I cannot dismiss. It’s driving me up the wall. Can you tell me how to get rid of the error at the top of every single page that states "ACF — ACF now automatically escapes unsafe HTML when rendered by the_field or the ACF shortcode. We’ve detected the output of some of your fields has been modified by this change, but this may not be a breaking change. Learn more. Show details."

    • Liam says:

      Hey Phil,

      If you’re happy nothing is broken, you can add the code listed above to disable the notification. This message will be disabled by default in ACF 6.3 due out in the next couple of months.

      add_filter( 'acf/admin/prevent_escaped_html_notice', '__return_true' );

  • Fernando Fas says:

    Hi there, we implemented the codes suggested and now is duplicating the content when rendering on the screen. Any idea why that is happening?

  • Erish (ErishV) Vital says:

    After applying the echo wp_kses_post( get_field(‘field_name’) ); and echo wp_kses_post( get_sub_field(‘field_name’) ); to all the affected areas, will the notification be updated as well? Or do I need to filter the notification completely? How do I know if an issue occured?

    • Liam says:

      Hey Erish,

      If you clear the notification, it will only come back if there are still instances of the_field.

      By swapping your code, you’ve essentially moved to handling any escaping yourself, which you should have only done when you confirmed each field shouldn’t contain HTML. At this point, your best idea is to just manually check nothing has broken on the site.

      Thanks, Liam

  • Society for Women's Health Research says:

    We have ACF Pro 6.2.7 and are having issues with seeing miscellaneous text at the header and footer of our website now.

    I know it is because the Google Tag Manager code we are using is erronously using the <script> code in the field, but I don’t know how to fix it. Can you help?

    This is the Google Tag Manager code we are using:

    <!– Google tag (gtag.js) –> <script async src="https://www.googletagmanager.com/gtag/js?id=G-USERCODE"> </script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag(‘js’, new Date());

    gtag(‘config’, ‘G-USERCODE’); </script>

    • Liam says:

      Hey there! You’ll need to find where the code is being output in your theme, replacing the_field(x) with echo get_field(x)

      If it’s in the header and footer of every page, it’s likely in header.php and footer.php.

  • Daniel says:

    Why do you recommend us to change the_field to echo get_field (or with escaping) when the_field does that now? It’s very confusing for all of us who already thinks about security. I think a better recommendation would be to keep the_field and add proper escaping for unsecure html when necessary. I see a lot of blog posts telling people to replace the_field with echo get_field. It will only make most sites more insecure!

    Seems like the focus now is to not use the_field – just to get rid of the warning. You could have explained it a lot better. And also ignored giving a warning when secure things like "&" is replaced.

    Lots of warnings in all my clients sites now but actually no change is needed, but I’ve invested a lot of time in this but everything is fine and all I actually needed was to disable that warning-notice.

  • Milena LunaDesign says:

    hi! I have a question how to disable this release in subfiled, I have analytics_code (Analytics Code) – rendered via the_sub_field ‘acf/the_field/allow_unsafe_html’, function( $allowed, $selector, $post_id, $field_type, $field_object ) { if ( $selector === ‘analytics_codes/analytics_name’ || $selector === ‘analytics_codes/analytics_code’ ) { return true; } return $allowed; }, 10, 5 ); but it didnt work, on my website scripts form head are moved to body and i have plain text on my website

  • mufc4everch says:

    Hello,

    I am having trouble with this. We have youtube iframes that we want to output. I’ve tried changing the fields to Oembed and WYSIWYG fields and still it’s being escaped as in the iframe is not showing up in the front-end.

    We deploy the codes using short codes and Divi so I’m not sure what to with all the php references in this document. For example we have the line [acf field="bio"]

    I’ve added the following, as per the comments below to my functions.php file but it doesn’t do anything

    add_filter( ‘acf/the_field/allow_unsafe_html’, function() { return true; }, 10, 2); echo wp_kses_post( get_field(‘video’) ); echo wp_kses_post( get_field(‘bio’) );

    Please help, this is very frustrating as we want to display these youtube iframes.

    • Liam says:

      Hey there, contacting our support team is your best bet now this has been out for a while, we’re not actively monitoring this thread.

      That said, the acf/the_field/allow_unsafe_html function is only for the_field() functions. You want acf/shortcode/allow_unsafe_html to apply it to the shortcode.

      The filter also requires you to return true or false. If true, the output will be allowed. So you want something like the examples earlier in the comments:

      add_filter( 'acf/shortcode/allow_unsafe_html', function ( $allowed, $atts ) { if ( $atts['field'] === 'youtube_field_name' ) { return true; } return $allowed; }, 10, 2 );

  • holdusback says:

    Hey there,

    I have this special message using a shortcode on an URL field, rendering via a shortcode on a custom post type page.

    I dont rly get how I fix this ? It dont have any iframe, script or stuff like that, its just a normal https URL.

    Hope you can help !

  • WoodyP says:

    Hello Liam, thanks for the explanation, I have some doubts about how to modify my code, what should I write now instead of get_field? These are the codes I’m using. Thank you!

    — $post = get_post(get_the_id()); $author_id = $post->post_author; if( !empty(getfield(‘test’,’user‘.$author_id)) ){ $nametest = getfield(‘test’,’user‘.$author_id); $authorurl = get_author_posts_url($author_id); echo ”.$authorurl.”.$nametest.”; } — — $post = get_post(get_the_id()); $trad_ext = get_field(‘namedemo’,$post); if( !empty($trad_ext) ){ if($trad_ext==’en’){ $postobj = get_field(‘namedemo_en’,$post); echo ‘<div class="namedemo_art"><a class="en" href="’.get_permalink($postobj).’">Read in English</a></div>’; } if($trad_ext==’it’){ $postobj = get_field(‘namedemo_it’,$post); echo ‘<div class="namedemo_art"><a class="it" href="’.get_permalink($postobj).’">Read</a></div>’; } } —