There are several cross site request forgery vulnerabilities in the Disqus WordPress Plugin, version 2.77.

Let’s start with the technical details, then I’ll get to the commentary.

Three settings in the admin interface lack nonces. By exploiting this you can activate or deactivate the plugin, and import or export comments between your wordpress database and disqus.

Example URLs:

http://wptestbox1.dev/wordpress/wp-admin/edit-comments.php?page=disqus&active=0

http://wptestbox1.dev/wordpress/wp-admin/index.php?cf_action=export_comments&post_id=0×tamp=1408220878.213

http://wptestbox1.dev/wordpress/wp-admin/index.php?cf_action=import_comments&last_comment_id=0&wipe=1

These are all just simple GET requests. There is nothing terribly interesting in the plugin’s code related to this. It is just the simple lack of a nonce (for GET requests).



Recently, Nik Cubrilovic reported CSRF and XSS vulnerabilities in this plugin to Disqus. These vulnerabilities were fixed relatively quickly. That’s great, but these vulnerabilities were glaringly obvious and this plugin is several years old. They weren’t sanitizing input and they were using nonces in their form, but weren’t checking the value when the form was submitted. I’m not sure whether the nonce issue was simply an oversight that went unnoticed for years, or was the result of a lack of understanding about how nonces (for CSRF protection) work or how wordpress plugins should be using them. Either way, when Nik Cubrilovic informed them of the problem in June and they released a new version, I would at least expect it to be fixed correctly, especially considering how simple (and obvious) the problem is. They now verify the nonce for all POST requests, but not for GET requests.

You can take a look at the changes that were made to fix the issues reported by Nik here. The update added this code to check for nonces:

if ( ! empty($_POST) ) { $nonce_result_check = has_valid_nonce(); if ($nonce_result_check === false) { die('Unable to save changes. Make sure you are accessing this page from the WordPress dashboard.'); } }

And it also changed this:

// handle disqus_active if (isset($_GET['active'])) { update_option('disqus_active', ($_GET['active'] == '1' ? '1' : '0')); }

To this:

// handle disqus_active if ( isset($_GET['active']) ) { update_option('disqus_active', ($_GET['active'] == '1' ? '1' : '0')); }

Notice the change is spacing around ‘isset’? The formatting in the source isn’t consistent is this regard so I doubt this change was completely automated. Someone (most likely) looked right at code vulnerable to CSRF and didn’t recognize it. This change was made in the same release that was made primarily to fix CSRF. I don’t know whether this is funny or scary.

Links:

Nik Cubrilovic’s Blog Post on the CSRF and XSS Vulnerabilities he reported.

Disqus WordPress Plugin

Disqus’ Website