False Vulnerability Report: User Submitted Posts [Persistent XSS]
As part of our cataloging the vulnerabilities in WordPress plugins for our service we come across false reports of vulnerabilities from time to time. So that others don’t spend their time looking over these as well we post our findings on them.
The explanation of how the claim of a persistent cross-site scripting (XSS) vulnerability in the User Submitted Posts plugin ended up being false is good reminder that people trying to discover security vulnerabilities should make sure that they use a clean WordPress install during testing, so they don’t contaminate their testing environment.
The report claimed that the post variable “user-submitted-content” was “not properly sanitized, thus allowing users to include JS code to submitted post content”.
Since the proof of concept for exploiting the vulnerability included with the report didn’t indicate what the JavaScript code should be in the input to cause the cross-site scripting vulnerability to occur, we did our testing using the following common piece of testing code:
<script>alert(document.cookie)</script>
After following the proof of concept steps we found that the new post created by the plugin did not contain cross-site scripting due to the <script> and </script> tags being removed from the input we submitted, the post content was instead this:
alert(document.cookie)
Since we were not sure if we had done something wrong, we next checked to see what changes were made in the new version of the plugin that was supposed to have this fixed the issue.
The line of code that brings the content of “user-submitted-content” into the plugin
if (isset($_POST['user-submitted-content'])) $content = stripslashes($_POST['user-submitted-content']);
was changed to
if (isset($_POST['user-submitted-content'])) $content = usp_sanitize_content($_POST['user-submitted-content']);
The usp_sanitize_content function that the input is put through there was also added:
// sanitize post content function usp_sanitize_content($content) { $allowed_tags = wp_kses_allowed_html('post'); return wp_kses(stripslashes($content), $allowed_tags); }
When we ran the cross-site scripting code from before through the usp_sanitize_content function, the result was:
alert(document.cookie)
So all the change did was to change when the user input is sanitized, but it was sanitized in either case, so there didn’t seem to be a vulnerability. At that point we contacted the person who put out the report claiming there was a vulnerability to see if maybe they were entering different JavaScript code that was not being sanitized, which would explain the discrepancy. After several emails back and forth we didn’t find out what code they were using, but they did say that we were right that sanitization was occurring all along and they explained that their error must have been due to them “testing some other plugins in parallel”.