A PHP file in your uploads folder is never supposed to be there

The uploads folder holds pictures and documents. It should never hold code. When it does, that code was almost always put there to run a backdoor.

An uploads folder of images, with one file quietly carrying a PHP tag highlighted among them.

WordPress writes uploads to wp-content/uploads: images, PDFs, the odd zip. Nothing there is ever meant to be executable PHP. So a .php file in uploads is one of the clearest signals of a compromise there is, and attackers know the folder is writable, rarely watched, and excluded from most integrity checks.

The shapes it takes

  • Plain PHP, oddly named. A file like wp-content/uploads/2026/10/.cache.php or icon-cache.php, holding a web shell that runs whatever a request sends it.
  • Polyglot images. A real image header followed by PHP, saved as .ico, .gif or .png. It opens as a picture and runs as code. A favicon named .f4812a.ico is a classic.
  • Payloads inside fonts or compressed blobs. PHP or a zlib-compressed loader tucked into a .woff, .ttf or .dat file that something else pulls in.
  • Execution overrides. A .user.ini or .htaccess in an uploads subfolder that sets auto_prepend_file, or AddType application/x-httpd-php .jpg, so the server runs images as PHP.

Finding them by hand

List executable code where only media belongs:

find wp-content/uploads -type f \( -name '*.php*' -o -name '*.phtml' \)
grep -rl '<?php' wp-content/uploads
find wp-content/uploads -name '.user.ini' -o -name '.htaccess'

Anything the first two commands return is worth opening. A .user.ini or .htaccess deep in uploads almost never belongs there. Do not just delete what you find until you have a copy: a backdoor is also evidence of how they got in.

What the R7 radar reads

OwnerTrail treats uploads, and the other folders where code never belongs, as code-free zones. Any PHP there is reported as unexpected. Beyond the name, it reads the file for the shapes malware takes, the same way a human reviewer would:

  • PHP after an image or font header (a polyglot), and compressed or encoded payloads.
  • Code that runs, decodes or includes whatever a request sends it.
  • .htaccess and .user.ini rules that switch PHP execution back on.
  • The same reading applied to the files that run before WordPress, such as wp-config.php and index.php, whose contents never leave the file.

On a very large uploads folder it works in short time-slices and picks up where it left off, so even tens of thousands of files get read without stalling the site.

Quarantine, not delete

Finding the file is half the job. With OwnerTrail Pro you move an unexpected file into a sealed vault in one click: it is taken out of the web root into a folder the server refuses to serve or run, under a random name with no extension, and it can be put back if you were wrong. Nothing is destroyed, and the file stops running at once. The files that would take the site down if moved, WordPress's own start-up files and known firewall bootstraps, are never touched.

Related: the Japanese keyword hack and how to check your files are genuine.