What do the five verdicts mean?

Most scanners have two answers: clean and infected. Shelltrap has five, because a resource limit is not the same statement as "nothing found", and a broken scanner is not the same statement either.

The five verdicts

  • clean — scanned by every engine the active profile provides, nothing found. Default action: none.
  • suspicious — several independent signals, below the action threshold. Default action: report.
  • malicious — a signature or hash match, or a heuristic score above the threshold. Default action: quarantine for signature and hash hits.
  • unscanned — a limit was hit (file size, scan time, archive depth, entry count, expansion ratio). The reason is recorded and the object is queued for a bounded deep scan.
  • degraded — the scanner itself was impaired: clamd gone, a worker dead, a rule set missing, a namespace fallback. Default action: report and alarm.

unscanned and degraded are never displayed as clean. That makes some dashboards less green; it also makes them true. An impaired scanner or a clamd outage must never be read as a clean scan.

How a verdict is reached

Inside the sandboxed worker, in order: type detection by magic bytes (which steers priority only), ClamAV over the local socket in the full profile, YARA 4.5 with rules precompiled for exactly that engine version, SHA-256 hash sets with a known-good allowlist, and heuristics with per-signal scoring.

The known-good allowlist covers WordPress core, widely used plugins and themes, Laravel and Joomla. It may not blindly override a path-context hit: a known-good hash sitting in an uploads directory is still a finding.

Why heuristics need more than one signal

A heuristic hit requires several independent signals. Entropy on its own, or one long line on its own, never produces a suspicious verdict — that lesson cost us a handful of false positives on ordinary JPEGs and on Wordfence's own transient cache, and it is fixed. Every finding shows the signals that produced it, so a verdict is something you can inspect rather than something you have to trust.

Why a signature update changes old verdicts

Verdicts are cached, and the cache key contains the mount ID, the inode, high-resolution mtime and ctime, the size, the content hash and the rule set, engine and policy generations. So a new signature generation automatically invalidates yesterday's clean verdicts: a file that was clean under yesterday's rules has not been scanned under today's.

Path-dependent policy verdicts live in a separate cache, because context can change without the content changing at all. The same inode can appear in a new place through a hard link or a rename, and "PHP in an uploads directory" is a statement about the place, not about the bytes.

Where to see them

shelltrap findings list
shelltrap findings list --json
shelltrap metrics | grep shelltrap_scans_total

In the metrics, shelltrap_scans_total{verdict} should be dominated by clean; if unscanned grows, look at the reason spread rather than the total.


Was this article helpful?

mood_bad Dislike 0
mood Like 0
visibility Views: 0