Coordinated plugin updates to address security vulnerability in many popular WordPress plugins

A coordinated plugin update occurred this morning between many popular WordPress plugins to address a common security vulnerability that allows for XSS cross-site scripting attacks.

The common vulnerability that triggered a coordinated plugin update of many popular plugins this morning is caused by a lack of escaping of two WordPress functions, add_query_arg() and remove_query_arg().

It appears it was a common misunderstanding that the functions needed additional escaping when in use, and the WordPress Codex documentation for the functions did not show proper escaping in the example use cases for several years.

The exact number of plugins affected is unknown, but a number of the most popular WordPress plugins are affected.

The vulnerability was originally disclosed to the team at Yoast by Johannes Schmitt of Scrutinizer CI. Joost de Valk took the issue to their security partner, Sucuri, and together they understood that the issue could affect far more than plugins than WordPress SEO and Google Analytics by Yoast.

They worked with WordPress lead developer and WordPress.org plugin team member Dion Hulse to evaluate how many other top plugins may be vulnerable. Combined, Joost notes in his security notice post that 44 people joined a dedicated WordPress Slack channel to work on the updates, which resulted in the coordinated release.

Millions of websites affected

Millions of websites are vulnerable due to this issue. Jetpack and Yoast’s WordPress SEO alone are active on well over a million websites.

Sucuri has identified a minimum of fifteen plugins affected, but they note they’ve only looked into the top “300-400” and others that were notable.

In all likelihood, many more plugins than those listed will have similar vulnerabilities. add_query_arg() and remove_query_arg() are relatively common functions in advanced WordPress development.

Not always a high risk vulnerability

It’s hard to speak for exactly how high risk the mis-use of the functions could be, as they are used in different ways in different plugins; and even within a certain plugin codebase, they could be used many times and have different risk levels in each instance.

Escaping is a fundamental development principal. One of my favorite coffee mugs (pictured above) is from WordPress.com VIP and says, “Sanitize early, escape late, and drink often.”

It is therefore concerning that there was such broad misuse of a WordPress function for so long, and it went unchecked in the Codex.

The Codex previously had examples without escaping, and it had no indication whether the return value was escaped or not. It simply stated that the return value as, “New URL query string.”

This has been updated, both in the examples and the return value section, to note that it can potentially return unescaped data.

New URL query string. Note that this string may contain unescaped data not intended for a URL, especially if the data added comes from user input. The result should be passed through esc_url() before being output as HTML, in a link.

That said, of the developers I’ve spoken to, even with the vulnerabilities in place they say that the risk of exploitation is small, due to the privileges required of users to attack. Though it is important to note that that is no guarantee, and it is important to update your plugins if you have updates available.

The Codex is a wiki. It’s not a fundamental issue of WordPress that this was poorly documented, however it does point to some of the problems that have been noted for some time in regard to the value of the Codex. In fact, just this morning the Codex page for add_query_arg() was redirected to the new developer.wordpress.org page for the function instead.

Eventually, the Codex will go away for most functions that can point to the new developer reference.

Five plugins opting in to forced updates

Jetpack, Easy Digital Downloads, P3 Plugin Profiler, Download Monitor, and Related Posts for WordPress are all opting in to automated forced updates from WordPress.org. This means that these plugins have created new releases for each major branch of their plugins to be distributed and automatically updated by the WordPress.org team.

Other plugins are not opting in. Notably, Yoast did not opt in for WordPress SEO or their Google Analytics plugin. Joost de Valk cites concerns that some site owners had their plugins deactivated during the last forced upgrade process they went through.

Indeed, my own site has had plugins deactivate when forced updated each time it’s occurred. I took this issue to members of the WordPress.org update team, and was told that they believe it is an edge case occurrence, and that while they are monitoring new updates, there is not currently a plan to change practices for the updates. I will be very interested with the updates today how commonly this happens.

Other posts and resources

I will continue to collect plugin update posts, changelogs, and other resources for this update. If you run a WordPress website, these updates will likely affect you.

There is no reason for panic or to be too concerned, but you should update your plugins as soon as you can to reduce your risk of vulnerability.