Why web shells are hard to find honestly
A web shell is PHP, and so is everything legitimately around it. A scanner keyed on dangerous functions flags every minified library, every plugin that calls eval, every framework that decodes base64, and an alert stream that is mostly false positives is one nobody reads. The real failure of web-shell detection is not missing the shell; it is being switched off a month after it is installed.
SecAI says this about itself too. When the web-shell findings on SecAI's own fleet were reviewed, every one had been a false positive. The response to that was not a higher threshold; it was a rule that the dangerous action, making a customer's file unreadable, always waits for a person who can see the evidence.
What the scanner looks at
- The usual web roots for the distribution, /var/www, /var/www/html, /srv/www, /usr/share/nginx/html, and every /home/<user>/public_html that exists, so cPanel-style hosting layouts are covered.
- PHP files, against rules that require a combination rather than one function: a command-execution call together with /dev/tcp and a shell path is a reverse shell; an eval over a base64 payload is an encoded dropper; a mail call built the way spam mailers build it is a mailer.
- PHP files modified recently, because a file that changed yesterday in a directory that has not changed in a year is worth a look whatever it contains.
- Shell scripts in web roots, for miner and reverse-shell markers. JavaScript, JSON and configuration files are not scanned, because build tools make them look malicious all day.
Screening before it reaches you
A candidate is not a finding. The agent sends the path, the rule that matched, the size, the SHA-256 and the first 200 bytes of the file, and the platform screens it: is the path inside WordPress core or a known plugin, is the rule one that misfires on minified code, does the excerpt look like a real shell or like a library. The verdict is real threat, suspicious or false positive, with a confidence, and only the first two become findings. The excerpt is the only file content involved, and it is the second of the two cases in which any file text leaves the server; the Trust Center states both.
The file change that came first
Independently of the rules, the agent hashes files in served directories and reports a change with the hash before and after. On WordPress it checks core, plugin and theme files against a knowable expected state, which is why a modified core file is unambiguous in a way a modified application file is not. A web shell is usually a new file in an uploads directory or an edit to an existing one; file integrity sees both even when no rule matches.
Quarantine, never delete
The proposed action for a web shell is quarantine: a copy is kept, and the file is made unreadable where it is, owned by root, not moved and not deleted. Quarantine is never pre-approved, it waits for a person even when a person asked for it, because two hundred bytes are enough to recognise something and not enough to prove it, and an unreadable file can take a site down. Restore puts it back, never needs approval, and refuses only if the file was changed after quarantine. SecAI does not clean or rewrite application files.
Why it keeps coming back
Removing the shell is half the job. The intruder who placed it usually also left a cron line, a systemd timer, an authorised key or an extra account that puts it back, and cleanup that only touches the web directory produces a server that is compromised again within days. SecAI watches those persistence paths with the text before and after a change, so the second half is found.
Limits
- PHP and shell scripts only. A web shell written in another language is caught by file integrity and behaviour, not by the content rules.
- Not a web application firewall: it does not see or block the request that uploaded the shell.
- Not a cleaner: it never edits or deletes your application's files.
- Web-shell scanning is part of the Pro plan and above.