Security updates for our GA and SEO plugins & many others

In this post, we’re announcing a security update to both our SEO plugin and our Google Analytics plugin. Chances are, a few of the other plugins you use are affected too. Read on below if you’re interested in the how and why, but make sure you go into your WordPress admin and update. Don’t just update our plugins, update all of them!!

The backstory

There are several issues fixed in these releases, so we’ve got individual release posts for WP SEO and for our GA plugin. The main issue we’re fixing with this release is the wrong usage of add_query_arg and remove_query_arg we had in both our WordPress SEO plugin and our Google Analytics by Yoast plugin.

This issue was responsibly disclosed to us by Johannes Schmitt of Scrutinizer CI (thank you!!), who found it in our SEO plugin. We discussed it with our partners at Sucuri. At first we thought it wasn’t exploitable, later on we found it allowed for XSS. In our case, you needed to be logged in as an admin to be XSS’ed, but still this was an issue to fix.

I, Joost, created the particular problem myself and was wondering how that had gotten by me, when I figured out that both the Codex and the developer documentation on for these functions were missing the fact that you had to escape their output. In fact, the examples in them when copied would create exploitable code straight away. I spoke to Samuel, mostly known in the WordPress community as Otto42, and he fixed the codex. A day later, the developer docs were amended as well.

We were ready to do a security release last Wednesday. I was hesitant as I was guessing that more people had made the same mistake, because of the documentation. I talked to Dion Hulse, one of the people on the plugins team, and started doing a search, together with the team at Sucuri. We quickly found we were far from the only one.

A coordinated security release

As we researched, we quickly identified a few dozen affected plugins, lots of them major; the affected plugins include Gravity Forms, Easy Digital Downloads, Jetpack, WP e-Commerce, All In One SEO pack and that’s just some of the big ones. Based on this info Daniel Cid at Sucuri and myself started reaching out to those plugin developers and coordinating a big security update between all of us. WordPress Slack proved to be very helpful for this kind of coordination.

Some of these plugins had XSS issues on the frontend. We did not, so when the core team offered to do an automatic update, we opted out. The last time we did an automatic update (this is an update your WordPress installs automatically without your intervention), our WordPress SEO plugin got disabled on hundreds of sites and we didn’t want that to happen. Choices like these are tough to make: some sites might have a minor security issue now, but for many sites not having our SEO plugin enabled might actually be worse.

I must say I’m quite proud of the community getting together like this and coordinating a release in such a fluent way. There are in total 44 people in the Slack group coordinating this release, and everyone is being very professional in dealing with it. After all, we’re updating dozens of plugins, and most of them had only 3 to 4 days notice, including a weekend. All these  WordPress plugin developer working together with the WordPress core security team, makes me proud to be a part of this community!

For users: I don’t see the update yet!

If you don’t see the update yet, go to your wp-admin/update-core.php page, under Dashboard → Updates, this will clear the cache for all updates and should then show you the updates for our plugins.

Going to this page will also make sure any automatic updates are done a few seconds later too. Be sure to check your plugins page a minute or so later to see if all the needed plugins are still active.

For developers: how to fix the issue

The short version for developers of how to fix this issue: if you’re using either add_query_arg or remove_query_arg without passing in the URL, it bases the URL it creates off of $_SERVER['REQUEST_URI']. In that process, it URL decodes the parameter names in the request URI, allowing for XSS. The solution is to simply wrap the output in esc_url and you’re done. Not a hard fix, but it has to be done.

If you think your plugin or theme is vulnerable and want to find out, feel free to reach out to me on WordPress Slack (I’m @joostdevalk there) and I’ll show you how to exploit it. As there are still bound to be vulnerable plugins and themes out there, I’m not going to explain that here.

This post first appeared as Security updates for our GA and SEO plugins & many others on Yoast. Whoopity Doo!