WPHammer
Log in
  • Scan context
  • Suppression rules
  • Reviewing findings
  • Related
  • Security Findings

    When WPHammer runs security scans, it produces individual findings — specific issues discovered on a site or server. The findings system aggregates these results, deduplicates them across scan runs, tracks their lifecycle, and lets you triage or suppress findings that are not actionable.

    Finding structure

    Each SecurityFinding records:

    • Type — what category of issue was found (FindingType enum: CoreIntegrity, PluginIntegrity, SuspiciousFile, FilePermission, Vulnerability, SuspiciousCron, Abandoned, AbusePattern)
    • Severity — how serious the finding is (FindingSeverity enum: Critical, High, Medium, Low, Info)
    • Status — where the finding is in its lifecycle (FindingStatus enum: New, Regressed, Dismissed, FalsePositive, Resolved, Suppressed)
    • Title and description — human-readable summary of the issue
    • File path — the specific file involved, if applicable
    • Signature — an xxh128 hash generated from the finding type and a unique identifier, used for deduplication across scan runs
    • Occurrence trackingoccurrence_count, first_seen_at, and last_seen_at track how often and when the finding has appeared

    For vulnerability-type findings, additional fields track:

    • CVE ID — the Common Vulnerabilities and Exposures identifier
    • Plugin slug — the affected WordPress plugin
    • Affected version and patched version — version range information
    • Patch status — whether a fix is available (PatchStatus enum)

    Finding lifecycle

    Findings move through a defined lifecycle:

    New findings

    When a scan discovers an issue for the first time, it creates a finding with New status. The signature ensures that if the same issue appears in a subsequent scan, it increments the occurrence_count and updates last_seen_at rather than creating a duplicate.

    Triage

    Team members can triage findings by calling triage() on the finding, which records:

    • The new status (Dismissed, FalsePositive, or Resolved)
    • The user who triaged it
    • Optional triage notes explaining the decision
    • A timestamp of when the triage occurred

    Regression

    If a previously resolved or dismissed finding reappears in a later scan, its status changes to Regressed and regressed_at is set. This surfaces issues that were thought to be fixed but have returned — a common scenario after plugin updates or restored backups.

    Active findings

    A finding is considered active (via isActive()) when its status is New or Regressed. These are the findings that need attention.

    Scan context

    Every finding belongs to a SecurityScan record that tracks the scan event itself:

    • Scan type — what kind of scan was run (ScanType enum: Full, Integrity, Files, Vulnerabilities, Crons, Abuse)
    • Status — whether the scan is pending, running, completed, or failed
    • Finding counts — aggregated counts by severity (critical, high, medium, low, info, total)
    • Timingstarted_at, completed_at, and duration_seconds

    When a scan completes, markAsCompleted() automatically counts findings by severity and stores the totals on the scan record. The worstSeverity() method returns the highest severity found, useful for quick assessment.

    Suppression rules

    For findings that are known and accepted — such as intentional file permission changes or expected custom code patterns — you can create suppression rules. The SecurityRule model defines team-level rules that automatically suppress matching findings:

    • Match type — which finding type to match (or * for all types)
    • Match pattern — a signature or glob pattern to match against
    • Match field — whether to match on signature or file_path
    • Scope — rules can be scoped to a specific server, site, or apply team-wide

    When isSuppressed() is called on a finding, it checks whether any active rule matches the finding's type, signature, and file path within the team's rules. Matched rules track how many times they have been applied (times_matched) and when (last_matched_at).

    You can create a suppression rule directly from a finding using suppressForTeam(), which generates a rule matching that finding's type and signature.

    Reviewing findings

    The security findings view aggregates findings across all scans for a site or server. Key review patterns:

    • By severity — critical and high findings should be reviewed first
    • By status — filter to active findings (New and Regressed) to see what needs attention
    • By type — group by finding type to batch-review similar issues
    • By recurrence — findings with high occurrence_count or recent regressed_at dates indicate persistent problems

    The dashboard Security tab provides a fleet-wide view of findings across all servers and sites.

    Related