Plugin Directory

Changeset 3167142


Ignore:
Timestamp:
10/11/2024 11:46:29 AM (18 months ago)
Author:
babbardel
Message:

Fixed Security Vulnerabilityon SVG Upload Handling

Location:
category-icon/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • category-icon/trunk/category-icon.php

    r2669691 r3167142  
    1313 * Domain Path: /lang
    1414 * Requires at least: 4.9.19
    15  * Tested up to:      5.9.0
     15 * Tested up to:      6.6.2
    1616 * Requires PHP:      5.6.40
    1717 */
     
    6363         * As we code this, WordPress has a problem with uploading and viewing svg files.
    6464         * Until they get it done in core, we use these filters
    65          * https://core.trac.wordpress.org/ticket/26256
    66          * and
    67          * https://gist.github.com/Lewiscowles1986/44f059876ec205dd4d27
    6865         */
    6966        add_filter('upload_mimes', array( $this, 'allow_svg_in_mime_types' ) );
     67        add_filter('wp_handle_upload_prefilter', array($this, 'sanitize_svg_upload'));
    7068        add_action('admin_head', array( $this, 'force_svg_with_visible_sizes' ) );
    7169
     
    8381        register_activation_hook( __FILE__, array($this, 'activate') );
    8482    }
     83
     84    /**
     85     * Handles the SVG upload process by sanitizing the file content,
     86     * generating a random filename, and preserving the original upload path.
     87     *
     88     * @param array $file The uploaded file information.
     89     * @return array The modified file information with sanitized content and updated filename.
     90     */
     91    public function sanitize_svg_upload($file) {
     92        // Check if the uploaded file is an SVG
     93        if ($file['type'] === 'image/svg+xml') {
     94            // Step 1: Read the original SVG content from the temporary file location
     95            $svg_content = file_get_contents($file['tmp_name']);
     96           
     97            // Step 2: Sanitize the SVG content to remove any potentially unsafe elements
     98            $clean_svg = $this->sanitize_svg_content($svg_content);
     99
     100            // Step 3: Extract the original file name (without extension) for use in the new name
     101            $original_name = pathinfo($file['name'], PATHINFO_FILENAME);
     102
     103            // Step 4: Sanitize the original name to ensure no special characters remain
     104            $sanitized_name = sanitize_file_name($original_name);
     105
     106            // Step 5: Generate a unique filename by appending a random suffix to the sanitized name
     107            $random_suffix = wp_generate_password(6, false);
     108            $new_filename = "{$sanitized_name}-{$random_suffix}.svg";
     109
     110            // Step 6: Overwrite the temporary file with the sanitized SVG content
     111            file_put_contents($file['tmp_name'], $clean_svg);
     112
     113            // Step 7: Update the file's displayed name, leaving tmp_name intact for WordPress to handle
     114            $file['name'] = $new_filename;
     115        }
     116       
     117        // Return the updated file information back to WordPress
     118        return $file;
     119    }
     120
     121    /**
     122     * Sanitizes SVG content by removing <script> elements and any unsafe attributes.
     123     * This helps mitigate potential XSS vulnerabilities from SVG uploads.
     124     *
     125     * @param string $svg_content The raw SVG content to be sanitized.
     126     * @return string The sanitized SVG content.
     127     */
     128    private function sanitize_svg_content($svg_content) {
     129        // Create a new DOMDocument instance to parse the SVG XML content
     130        $dom = new DOMDocument();
     131       
     132        // Suppress XML parsing errors for invalid SVG formats
     133        libxml_use_internal_errors(true);
     134       
     135        // Load the SVG content into the DOMDocument for manipulation
     136        $dom->loadXML($svg_content, LIBXML_NOENT | LIBXML_DTDLOAD);
     137       
     138        // Clear any XML parsing errors
     139        libxml_clear_errors();
     140       
     141        // Step 1: Remove any <script> elements, which can execute JavaScript
     142        $scripts = $dom->getElementsByTagName('script');
     143        while ($scripts->length > 0) {
     144            $scripts->item(0)->parentNode->removeChild($scripts->item(0));
     145        }
     146
     147        // Step 2: Remove unsafe attributes that could contain JavaScript (like onclick, onload)
     148        $xpath = new DOMXPath($dom);
     149        foreach ($xpath->query('//@*') as $attr) {
     150            if (stripos($attr->name, 'on') === 0 || stripos($attr->value, 'javascript:') === 0) {
     151                $attr->parentNode->removeAttribute($attr->name);
     152            }
     153        }
     154
     155        // Return the sanitized SVG content as XML
     156        return $dom->saveXML();
     157    }
     158   
     159   
    85160
    86161    /**
  • category-icon/trunk/readme.txt

    r2669691 r3167142  
    33Tags: category, taxonomy, term, icon, image
    44Requires at least: 4.9.19
    5 Tested up to: 5.9.0
     5Tested up to: 6.6.2
    66Requires PHP: 5.6.40
    77Stable tag: 1.0.0
Note: See TracChangeset for help on using the changeset viewer.