When I trace how an attacker first got code onto a WordPress server, an upload feature is often involved. A contact form that accepts attachments without checking them. A profile picture field in a membership plugin that trusted the file extension. A custom upload script a developer wrote years ago and forgot about. Each one gave an attacker a way to place a file on the server, and sometimes to run it.
File uploads are necessary on many sites: media for content, documents in support forms, CVs on job pages, avatars on community sites. They just need to be handled carefully. Here’s how WordPress protects uploads, where the gaps are and how to close them.
How WordPress restricts uploads
By default, WordPress only allows certain file types to be uploaded through the media library, based on a list of allowed extensions and MIME types. Common images, documents, audio and video formats are allowed. Executable types, like PHP files, are not.
WordPress also checks that a file’s extension matches its actual content where it can, using the wp_check_filetype_and_ext function. A file named photo.jpg that’s really a PHP script should be rejected.
Users without the unfiltered_upload capability are limited to these allowed types. On single sites, even administrators are restricted unless a constant called ALLOW_UNFILTERED_UPLOADS is set. Don’t set it. It removes an important safety net and gives any compromised admin account the ability to upload anything.
Changing allowed file types safely
Sometimes you need to allow additional types, such as a particular document format. Use the upload_mimes filter to add only what you need, and only for users who need it:
You can also remove types you don’t want, reducing the attack surface. A site that never needs audio uploads doesn’t need to allow them.
Why SVGs are special
SVG images are popular for logos and icons because they’re small and sharp at any size. But SVG files aren’t simple images. They’re XML documents that can contain JavaScript, links and references to external resources.
A malicious SVG can include script code that runs when the image is opened directly in a browser. If an attacker uploads such a file and an administrator views it, the script can act with the administrator’s privileges, for example creating a new admin account. This is a form of stored cross-site scripting.
That’s why WordPress doesn’t allow SVG uploads by default.
Allowing SVGs safely
If you need SVG uploads:
- Use a solution that sanitises SVGs on upload, stripping scripts, event handlers and external references. Several plugins do this. Simply adding SVG to the allowed types without sanitising is not safe.
- Restrict SVG uploads to trusted roles, such as administrators and editors.
- Serve SVGs with appropriate headers. A Content Security Policy and headers like X-Content-Type-Options: nosniff add further protection.
- Prefer inline SVGs in theme code for icons, where you control the content, rather than accepting SVG uploads from users.
Never allow SVG uploads from untrusted users, such as customers or form visitors.
Uploads through forms
Form plugins often include file upload fields for attachments, CVs or images. These can be risky because they’re usually available to anonymous visitors.
Restrict file types tightly
Allow only the specific types you need. A CV upload field might accept PDF and DOCX only. An image upload field might accept JPG, PNG and WebP only. Never allow “any file type”.
Limit file size
Set a maximum size that matches what you expect. Large uploads can fill disks or be used to stress the server.
Check where files are stored
Some form plugins store uploads in publicly accessible folders with predictable URLs. That’s a privacy risk if forms collect personal documents, like CVs or identity documents. Prefer plugins that store uploads in protected locations, randomise filenames and serve files only to authorised users.
Consider not storing files at all
If uploaded files only need to reach your inbox, some form setups can attach them to notification emails and then delete them, or send them directly to a secure external storage service. Fewer stored files means less risk.
Protect against spam and abuse
Upload fields attract bots. Use the same spam protection as your other forms: honeypots, invisible challenges and rate limiting.
Block PHP execution in upload folders
Even with good validation, defence in depth matters. Make sure files in wp-content/uploads can never be executed as PHP. If an attacker finds a way to upload a PHP file disguised as something else, it simply won’t run.
On Nginx:
| <code>location ~* /wp-content/uploads/.*\.(php | phtml | phar)$ { |
|---|
On Apache, in an .htaccess file inside the uploads folder:
| <code><FilesMatch "\.(php | phtml | php5 | php7 | phar)$"> |
|---|
Apply the same protection to any custom upload folders plugins create outside wp-content/uploads.
Uploads in custom code
If you write code that handles uploads, use WordPress’s upload functions rather than handling files yourself:
Key points:
- Check capabilities and nonces before processing.
- Use wp_handle_upload or media_handle_upload, which apply WordPress’s file type checks and generate safe filenames.
- Restrict MIME types to exactly what you need using the mimes override.
- Never trust the filename or type sent by the browser. Both can be faked.
- Never use move_uploaded_file directly into a web-accessible folder with the original filename.
- Store sensitive uploads outside the web root or in protected folders, serving them through a script that checks permissions.
Image processing risks
Image processing libraries occasionally have vulnerabilities triggered by specially crafted files. Keep your server’s image libraries, like GD and Imagick, updated along with PHP. Use your host’s or operating system’s security updates.
Scan uploaded files
For sites that accept documents from the public, consider malware scanning of uploaded files. Some hosts and security tools scan uploads automatically. Documents with malicious macros won’t harm your server, but they can harm staff who open them, so treat unexpected attachments with care.
Clean up regularly
Uploaded files accumulate. Review upload folders periodically:
- Look for unexpected file types, especially PHP files, which should never be there.
- Remove old form uploads you no longer need, in line with your data retention policy.
- Check for large files filling disk space.
A real-world pattern
One upload-related compromise I investigated started with a job application form on a recruitment site. The form plugin allowed “documents”, and its file type check only looked at the extension in the filename. An attacker uploaded a file named like a document that was actually a PHP script, then requested it directly from the uploads folder. Because PHP execution wasn’t blocked there, the script ran and gave the attacker full control of the account.
Three layers would each have stopped the attack on their own: strict file type validation that checked the file’s real content, storage outside the public uploads folder and a server rule blocking PHP execution in uploads. None were in place. After the cleanup, we added all three, plus malware scanning of uploaded files and an alert whenever an executable file appeared in an upload folder.
The lesson is that upload security works best in layers. Validation can have bugs, plugins can have vulnerabilities and configurations can drift. When each layer is in place, a failure in one doesn’t become a compromise.
Review your upload features
Make a list of every place on your site where visitors or users can upload files: the media library, form plugins, profile pictures, support tickets, job applications, product reviews with photos and any custom features. For each one, note who can upload, which file types are allowed, where files are stored and who can access them afterwards. Many site owners are surprised how many upload points they have once they look.
Review this list whenever you add a new plugin or form, because new upload points tend to appear quietly over time, and each one deserves the same scrutiny as the media library.
Upload checks for agencies
If you manage several client sites, include upload points in your onboarding audit. Note every form or feature that accepts files, and confirm PHP is blocked in each storage folder before taking responsibility for the site.
Frequently asked questions
Is it safe to allow SVG uploads?
Only with sanitisation and for trusted users. Unsanitised SVG uploads can contain scripts that compromise administrator accounts.
Can a hacker upload a PHP file through the media library?
WordPress blocks PHP uploads by default and checks file contents. Vulnerable plugins or misconfigurations can bypass this, which is why blocking PHP execution in upload folders is an important extra layer.
Should I allow file uploads on my contact form?
Only if you genuinely need them. If you do, restrict types and sizes, protect stored files and use spam protection.
What’s ALLOW_UNFILTERED_UPLOADS?
A constant that lets administrators upload any file type. It removes an important protection and should be avoided.
Final thoughts
File uploads are powerful and risky. Keep WordPress’s default restrictions in place, allow only the file types you truly need, treat SVGs with special care, lock down form upload fields, block PHP execution in every upload folder and use WordPress’s upload functions in custom code. Review upload folders periodically. With these layers, upload features can serve your visitors without becoming an attacker’s way in.




