Protecting WordPress Media Library from Exploits
The media library is a common target for attacks. Learn how to secure your WordPress media files and prevent exploitation through uploads.
Media Library Security Risks
The WordPress media library stores all uploaded files and is accessible through multiple interfaces. Attackers target the media library because uploaded files can be executed by the server if not properly secured, and because users often trust files downloaded from websites they visit.
Common Attack Vectors
Malicious File Uploads
Attackers attempt to upload:
- PHP files disguised as images
- Webshells with modified extensions
- Polyglot files (valid image + executable code)
- Malware embedded in document metadata
Direct Access Exploitation
If PHP files are uploaded to the uploads directory, direct URL access can execute malicious code.
Metadata Attacks
Malicious code hidden in image EXIF data or document properties can exploit vulnerable image processing libraries.
Securing Upload Permissions
Restrict Who Can Upload
Limit upload capabilities to trusted users:
- Review user roles with upload permissions
- Remove upload capability from unnecessary roles
- Use custom roles for content contributors
File Type Restrictions
Limit allowed file types:
add_filter('upload_mimes', function($mimes) {
// Only allow specific types
return array(
'jpg|jpeg|jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
);
});
Preventing PHP Execution
Apache .htaccess Rules
Add to wp-content/uploads/.htaccess:
# Disable PHP execution
<Files *.php>
deny from all
</Files>
# Block all script types
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phps|cgi|pl|py|asp|aspx|shtml|sh|bash)$">
Require all denied
</FilesMatch>
# Disable script execution
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI
Nginx Configuration
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
location ~* /wp-content/uploads/.+\.(php|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ {
deny all;
}
File Validation
Content Type Verification
Validate actual file content, not just extensions:
add_filter('wp_handle_upload_prefilter', function($file) {
// Check actual MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$real_mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
$allowed_mimes = array('image/jpeg', 'image/png', 'image/gif', 'application/pdf');
if (!in_array($real_mime, $allowed_mimes)) {
$file['error'] = 'File type not allowed.';
}
return $file;
});
Image Validation
For images, verify they are valid:
// Verify image can be processed
$image = @getimagesize($file['tmp_name']);
if ($image === false) {
// Not a valid image
}
Strip Metadata
Remove potentially malicious metadata from images during upload. WordPress does this for some image types by default.
Secure File Serving
X-Content-Type-Options
Prevent MIME type sniffing:
Header set X-Content-Type-Options "nosniff"
Content-Disposition
Force downloads for certain file types:
<FilesMatch "\.(pdf|doc|docx|xls|xlsx)$">
Header set Content-Disposition attachment
</FilesMatch>
Media Library Monitoring
Scan for PHP Files
Regularly scan uploads for executables:
find wp-content/uploads -name "*.php" -type f
Monitor New Uploads
Track all media uploads:
- Log uploader, filename, type
- Alert on unusual file types
- Review large upload batches
File Change Detection
Monitor existing files for modifications that could indicate injection of malicious code.
Cleanup and Maintenance
Remove Unused Files
Orphaned files increase attack surface. Clean up:
- Unattached media
- Old revision files
- Temporary uploads
Audit File Permissions
Ensure proper permissions:
- Files: 644
- Directories: 755
- No world-writable files
Third-Party Integration
External Upload Sources
If allowing external uploads:
- Apply same validation rules
- Scan for malware
- Rate limit uploads
CDN Security
If serving media through CDN:
- Configure CDN security headers
- Block PHP execution at CDN level
- Monitor for abuse
Conclusion
Securing the media library requires blocking PHP execution, validating uploads, monitoring for suspicious files, and maintaining proper permissions. These measures prevent attackers from using uploaded files to compromise your WordPress site.
Written by Sarah Chen
WP Folder Shield Team