Authenticated Persistent Cross-Site Scripting (XSS) via SVG in Embed Any Document
One of the changelog entries for the latest version of the WordPress plugin Embed Any Document is:
Fixed: Security issue with file uploading.
Looking at the changes made in that version, that appears to refer to restrictions placed on uploading SVG files. By default, the plugin no longer allows uploading SVG files. That can be re-enabled by adding a filter. The reason why uploading SVG files was removed relates to where the security fix as incomplete.
If a SVG file is being uploaded, new code tries to block the upload if the SVG file contains a script tag using a filter function wp_handle_upload_file_validation() (which is located in the file /awsm-embed.php):
639 640 641 642 643 644 645 646 647 | public function wp_handle_upload_file_validation( $file ) { if ( $file['type'] === 'image/svg+xml' ) { $svg_file = file_get_contents( $file['tmp_name'] ); if ( strpos( $svg_file, '<script' ) !== false ) { $file['error'] = esc_html__( 'Unsupported file content detected. Sorry, you are not allowed to upload this file.', 'embed-any-document' ); } } return $file; } |
If a script tag is in an SVG file, then JavaScript code can execute, which if done by a user not intended to be able to do that is cross-site scripting (XSS). With normal WordPress roles, only Authors have the ability to upload files but don’t have the unfiltered_html capability, which permits the equivalent of XSS, as well.
We said that the code tries to block script tags, but it doesn’t properly accomplish that. We thought the case sensitive check for the script tag would allow that to be bypassed, but in our testing the script tag needs to be lowercase, as checked for, for the code in the SVG file to run. The way it can be bypassed is that the code only runs if the “type” of the file being uploaded is image/svg+xml. The “type” is user input that comes from the request, so an attacker could send something else as the “type” when uploading an SVG file, which would cause the check for the script tag to not run.
We have notified the developer of that and offered to help them address that.
We tested and confirmed that our firewall plugin for WordPress protected against exploitation of this vulnerability, even before we knew about the vulnerability, as part of its protection against zero-day vulnerabilities.