Malware Removal

WordPress File Upload Security: Preventing Malware Uploads

Secure file uploads in WordPress by validating file types, scanning for malware, and restricting upload permissions.

S
Sarah Chen
7 min read
1,467 views
WordPress file upload security and malware prevention guide

File uploads are a common attack vector. Attackers upload PHP shells disguised as images or exploit vulnerable upload handlers to gain server access.

File Upload Attack Vectors

Common Attack Methods

  • PHP files disguised as images (shell.php.jpg)
  • Double extensions (image.jpg.php)
  • Null byte injection (image.php%00.jpg)
  • Content-type spoofing
  • SVG with embedded JavaScript
  • Polyglot files (valid image + valid PHP)

WordPress Upload Validation

Default Allowed Types

// WordPress default allowed mime types
// Images: jpg, jpeg, png, gif, ico, webp
// Documents: pdf, doc, docx, ppt, pptx, xls, xlsx
// Audio: mp3, m4a, ogg, wav
// Video: mp4, m4v, mov, wmv, avi, mpg

Restrict Upload Types

// Limit allowed upload types
add_filter('upload_mimes', 'wpfs_restrict_uploads');
function wpfs_restrict_uploads($mimes) {
    // Remove potentially dangerous types
    unset($mimes['svg']);
    unset($mimes['svgz']);
    unset($mimes['exe']);
    unset($mimes['htm']);
    unset($mimes['html']);

    // Only allow specific types
    return array(
        'jpg|jpeg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'pdf' => 'application/pdf',
    );
}

Enhanced File Validation

Verify Actual File Type

// Check actual file content, not just extension
add_filter('wp_handle_upload_prefilter', 'wpfs_validate_upload');
function wpfs_validate_upload($file) {
    // Check file extension
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

    // Get actual mime type from file content
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $actual_mime = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);

    // Verify image files are actually images
    $image_mimes = array(
        'image/jpeg', 'image/png', 'image/gif', 'image/webp'
    );

    if (in_array($ext, array('jpg', 'jpeg', 'png', 'gif', 'webp'))) {
        if (!in_array($actual_mime, $image_mimes)) {
            $file['error'] = 'File type does not match extension.';
        }
    }

    return $file;
}

Scan for PHP in Images

// Scan uploaded files for PHP code
function wpfs_scan_for_php($file_path) {
    $content = file_get_contents($file_path);

    $dangerous_patterns = array(
        '

Upload Directory Security

Disable PHP in Uploads

# .htaccess in wp-content/uploads/
<FilesMatch "\.php$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

# Alternative - deny all scripts
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phps|cgi|pl|py)$">
    Deny from all
</FilesMatch>

Nginx Configuration

# Disable PHP execution in uploads
location ~* /wp-content/uploads/.*\.php$ {
    deny all;
}

# Block access to hidden files
location ~ /\. {
    deny all;
}

File Size and Quantity Limits

Limit Upload Sizes

// Limit upload size per file type
add_filter('upload_size_limit', 'wpfs_upload_size_limit');
function wpfs_upload_size_limit($size) {
    // 2MB for regular users
    if (!current_user_can('manage_options')) {
        return 2 * 1024 * 1024;
    }
    return $size;
}

Rename Uploaded Files

Sanitize File Names

// Rename files to prevent execution tricks
add_filter('sanitize_file_name', 'wpfs_sanitize_filename', 10);
function wpfs_sanitize_filename($filename) {
    // Remove multiple extensions
    $parts = explode('.', $filename);
    if (count($parts) > 2) {
        $ext = array_pop($parts);
        $filename = sanitize_title(implode('_', $parts)) . '.' . $ext;
    }

    // Remove special characters
    $filename = preg_replace('/[^a-zA-Z0-9._-]/', '', $filename);

    return $filename;
}

User Permission Controls

Restrict Upload Capability

// Remove upload capability from certain roles
add_action('admin_init', 'wpfs_restrict_upload_role');
function wpfs_restrict_upload_role() {
    $contributor = get_role('contributor');
    $contributor->remove_cap('upload_files');

    $subscriber = get_role('subscriber');
    $subscriber->remove_cap('upload_files');
}

Front-End Upload Security

  • Always validate on server side
  • Use nonces for upload forms
  • Require authentication for uploads
  • Implement CAPTCHA for public uploads
  • Rate limit upload attempts

Conclusion

Secure file uploads require multiple validation layers: extension checking, mime type verification, content scanning, and execution prevention. Never trust file extensions alone.

Share:
S
Written by Sarah Chen

WP Folder Shield Team

Related Articles

What is the Japanese Keyword Hack? Complete Detection and Removal Guide
What is the Japanese Keyword Hack? Complete Detection and Removal Guide

Learn how to detect, remove, and prevent the Japanese keyword hack that creates thousands of spam...

January 20, 2026
How to Fix Chinese Spam Hack on WordPress - Step by Step Guide
How to Fix Chinese Spam Hack on WordPress - Step by Step Guide

Discover how to identify and remove Chinese spam injection from your WordPress website. This...

January 19, 2026
WordPress Pharma Hack: How Hackers Hijack Your Search Rankings
WordPress Pharma Hack: How Hackers Hijack Your Search Rankings

The pharma hack is a notorious SEO spam attack that injects pharmaceutical keywords into your...

January 17, 2026

Ready to Secure Your WordPress Site?

Get complete protection with WP Folder Shield.

Get Started