What we look for – the full rule list
This is the whole list. We keep no hidden rules – "all clear" means none of them found anything.
Rules 2026-10-08.3 · every account every 6 hours · 20 rules, 6 skipped classes
Threats — we name what we found
Wrong only when you did it on purpose. On a site the web reaches, we notify you.
- PHP script in an upload directory
- A .php file under wp-content/uploads (threat; under uploads/cache and in the directories plugins keep there for themselves — redux, aios, sucuri, fusion-builder, tcpdf_fonts — suspicious) or in an install's images/img/media/files/upload/download directory (suspicious). CMSes write no code there; attackers upload theirs through forms. The directory counts relative to the nearest install: a WordPress, Joomla, PrestaShop or Composer project placed under images/ is judged as an install, not as uploads. index.php placeholders (empty, a comment, header()+exit) are skipped.
- PHP code in a non-script file
- An .ico, .jpg, .png … file carrying a <?php tag (threat): a loader include()s it so the code does not show up where scripts are expected. A copy of a script (.bak/.old/.suspected/.php_/.php~) or an extensionless file with PHP in it is suspicious. A text, documentation, template or test-fixture file (.txt/.md/.html/.tpl/.twig/.stub/.dist/.fixed/.ini/.po…) with PHP in it is nothing — the server never runs it and documentation of PHP contains PHP; the signatures still read it. Cache directories and archives are skipped. The tag counts when text follows it — a chance “<?=” inside image data does not.
- .htaccess runs other extensions as PHP
- AddHandler/AddType/SetHandler mapping .ico/.jpg/.txt/.html/.js … onto PHP. A file with Options -ExecCGI next to it is the upload-directory lockdown, not a finding.
- auto_prepend_file / auto_append_file
- php_value auto_prepend_file in .htaccess or auto_prepend_file in .user.ini: the named file runs before every script of the site. The known plugin firewall stubs (wordfence-waf.php, aios-bootstrap.php) are suspicious.
- .htaccess serves PHP as text
- AddType text/plain .php, RemoveHandler .php or SetHandler default-handler, usually with Options +FollowSymLinks: the browser gets configuration files' source instead of their output. The ht7121 config grabber looked like this. Counts only in a directory holding a .php file — in an uploads directory without scripts it is the execution lockdown.
- A hoard of copied configuration files
- A directory with at least 10 *config*.txt / *configuration*.txt / *wp-config*.txt files: other sites' configuration files, passwords included, collected in one place.
- Known webshell
- Names and strings of known webshell families: c99, r57, WSO, b374k, FilesMan, IndoXploit, Alfa, p0wny, weevely, AnonymousFox — as whole words; Wordfence's rule set (wp-content/wflogs) is skipped.
- Modified WordPress core file
- A file in wp-admin/, wp-includes/ or the install root has a different checksum than wordpress.org publishes for the installed version (en_US and pl_PL). A file identical to another WordPress release's (a half-finished upgrade) is suspicious.
- File not shipped by WordPress core
- A script in wp-admin/ or wp-includes/ that wordpress.org does not ship in this version (threat); in the install root suspicious, because customers put their own files there. A file identical to another WordPress release's is suspicious.
- YARA signature
- The file matches a YARA rule from the signature bundle on the server — patterns of known webshell and backdoor families. The rule sources are listed below, each with its rule count and licence; the finding's detail names the source and the rule. A rule its author graded with a low score, and the generic rules the source lists as weak (big files with dynamic calls, callbacks), are suspicious only unless a specific rule hits too.
- Webshell signatures: signature-base (Nextron Systems)
- Florian Roth's and Arnim Rupp's public YARA rule set — the webshell part: generic PHP/ASP/JSP patterns (eval of request data, obfuscated payloads, code inside an image), the c99/r57/WSO/b374k/China Chopper/p0wny families, Chinese pentest kits, the php_zlib backdoor. Rules the authors score below 70 are graded suspicious. 819 rules from https://github.com/Neo23x0/signature-base@94a1c48d, licence DRL 1.1.
- Our own rules
- Patterns from what we find on our own fleet that the public sets do not cover — today SEO doorway pages (one content for the search engine's crawler, another for people). 1 rules, licence proprietary.
Suspicious — they look like an attacker technique
Ordinary code does this too, so they are listed to review — we notify only when someone requests such a file.
- User-Agent-conditional redirect
- RewriteCond on HTTP_USER_AGENT (googlebot/bing/yahoo) with a RewriteRule to an external URL: search engines see different content than people (SEO spam, pharma hack).
- Symlink out of the account
- A symbolic link pointing outside the account's home. Inside a container it reaches no other customer, but it is the config grabber's classic tool. A link to a socket (PostgreSQL/MySQL) is nothing.
- Obfuscated PHP
- eval(base64_decode(…)), gzinflate/str_rot13 inside eval, assert() or a function called from $_POST/$_GET — or two weaker signs at once: preg_replace with the /e modifier, create_function, chr()/\x.. chains, a long base64 blob. create_function or a \x.. chain alone is old, honest code. Legitimate code is written like this too (licensed plugins, ioncube), hence suspicious.
- Archive or database dump inside a site
- A .sql/.zip/.tar.gz/.rar file over 1 MiB inside a web-served directory: a backup, passwords included, downloadable by anyone who guesses the name. A directory holding 5 or more archives whose names do not say “backup” (downloads, camera dumps) is a data store, not a site backup — nothing.
- WordPress plugin without a readme
- A wp-content/plugins directory with one or two PHP files, no readme.txt and no subdirectories: backdoors posing as plugins look like this (suspicious; a plugin named with a random run of letters and digits — threat). So do hand-written plugins; a premium plugin has subdirectories.
- Modified plugin file
- A plugin file differs from the release wordpress.org publishes. Hand edits do this too, hence suspicious. When over 30% of the plugin's files differ it is a premium build or a fork under the same slug — one indicator on the plugin directory, no file-by-file comparison.
- File added to a plugin
- A script inside a wordpress.org plugin's directory that this release of the plugin does not contain.
- New file in mu-plugins
- A script directly in wp-content/mu-plugins — always loaded, absent from the plugin list a customer can deactivate. The known loaders (Installatron, WP Migrate DB, Elementor safe mode, Akeeba, AIOS) are nothing; a file named like WordPress core (class-wp-…) or with a random hex suffix (wp-cache-handler-3d7d1a7f.php) is a threat.
What we do not read
File classes skipped on purpose — and the ones scanned but with changes unreported, because they regenerate themselves.
- Session files unread
- PHP and framework sessions: transient data, not code; they change on every visit.
- Logs unread
- Log files grow continuously and are never executed.
- git/svn object stores unread
- Compressed repository objects: unreadable to signatures and not served.
- WordPress thumbnails unread
- Resized image copies (-800x600 …) under wp-content/uploads, generated by WordPress.
- Framework caches quiet
- WordPress/Laravel/Symfony/Magento/Joomla/Smarty cache directories, renamed ones included (var/@cache, var/1cache — how a PrestaShop forces a rebuild): scanned, but a change there is not reported — they regenerate themselves.
- node_modules quiet
- npm dependencies: thousands of files replaced wholesale by every install; scanned, changes not reported.
What the scanner is not
It is not an antivirus and is not sold as one: it checks files against this list and skips what it does not read — explicitly too. An empty list means “nothing from this list”, not “clean”. It does not replace backups or updates, and it never updates a vulnerable CMS on its own — it reports it.