📚 Plugin Documentation

Malware Scanner

Complete documentation for version 1.0.0 — scan your WordPress files and database for malware and receive alerts when threats are detected.

← Back to all documentation

Requirements

WordPress5.0 or higher
PHP7.4 or higher
PermissionsPHP must be able to read files across your WordPress installation (core, plugins, themes, uploads)
External DependenciesNone. No API keys, no third-party services. All scanning is done locally on your server

Installation

  1. Download the ZIP file from your account
  2. Go to Plugins → Add New → Upload Plugin
  3. Upload the ZIP and click Install Now
  4. Click Activate
On activation the plugin creates a quarantine directory, sets default options, and schedules automatic scans. No setup wizard needed.

Uninstalling

Deactivate and delete from the Plugins screen. The scheduled scan cron job is removed on deactivation. Options (ssp_malware_options, ssp_malware_scan_history, ssp_malware_ignored_threats) and the quarantine folder remain in the database and uploads directory. Remove these manually if you want a clean removal.

Quick Start

  1. Go to Malware Scanner in your WordPress admin sidebar
  2. Click the Run Scan Now button in the top-right of the header
  3. Wait for the scan to complete — a progress bar and live log show what's happening
  4. Review the results on the Dashboard tab
  5. Set up automatic scans in the Schedule tab so your site is monitored continuously
  6. Configure Email alerts so you're notified when issues are found
Your first scan may take 30 seconds to a few minutes depending on how many plugins and files your site has. Subsequent scans are typically faster.

Dashboard

The Dashboard tab is the main screen you see when opening the plugin. It shows a grid of status cards and your most recent scan results.

Status Cards

Site StatusShows “Clean” (green), “X Issue(s)” (red), or “Unknown” (yellow) based on the last scan
Last ScanDate/time the most recent scan ran, with duration
Files ScannedHow many files were checked in the last scan
Total ScansAll-time scan count, broken down into clean vs. issues
Issues FoundAll-time total issues detected across every scan
Next ScanWhen the next scheduled scan will run
QuarantinedNumber of files currently isolated in quarantine
IgnoredNumber of issues you've chosen to skip
Avg Scan TimeAverage duration and file count across all scans
Last IssueWhen the most recent issue was detected (“Never” if all scans have been clean)

Severity Legend

Below the cards is a color legend explaining the three severity levels: Serious (red), Suspicious (yellow), and Notice (blue).

Running a Scan

Click Run Scan Now from any tab. The Dashboard tab opens automatically and shows:

  • Progress bar — fills from 0% to 100% as the scan runs
  • Status text — shows what phase the scan is in (core files, plugins, themes, uploads, database, .htaccess)
  • Live log — a dark terminal-style area showing real-time scan activity

When the scan completes, the page reloads automatically after 1.5 seconds to show the fresh results.

Don't navigate away while a scan is running. The scan runs via an AJAX request — leaving the page will interrupt it.

Understanding Results

Scan results appear in the Recent Results section on the Dashboard. Each result shows:

TypeWhat kind of issue was found (e.g. “Malicious Code Detected”, “PHP File in Uploads”)
Severity BadgeSerious (red), Suspicious (yellow), or Notice (blue)
LocationThe full file path or database reference where the issue was found
DetailsA human-readable explanation of what was detected and why it's flagged

Up to 50 results are shown on the Dashboard. If more were found, a note at the bottom tells you to check the History tab for the full list.

Bulk Selection

Above the results is a Select All checkbox and a selected count. Check multiple items and click Ignore Selected to bulk-dismiss notices you've reviewed and trust.

Severity Levels

🔴 Serious Threat

Requires immediate action. These indicate code patterns actively used by hackers.

  • Malicious Code Detected — Dangerous patterns like eval(base64_decode(...)), shell_exec with user input, or nested obfuscation chains. These can give attackers full control of your server
  • PHP File in Uploads — Executable PHP files in the uploads directory where only images and documents should exist. Almost always injected by hackers
  • Disguised File — Files with double extensions like malware.php.jpg attempting to hide their true type
  • Suspicious Database Content — Injected <script> or <iframe> tags in your published posts that load external scripts
  • Suspicious .htaccess Rules — Directives like auto_prepend_file or auto_append_file that silently inject PHP into every page load

What to do: Quarantine the file immediately, then investigate. If you don't recognize it, it's likely malicious.

🟡 Suspicious

Needs review but might be legitimate.

  • Encoded .htaccess Content — Long encoded strings in your .htaccess file. Sometimes used by security plugins or CDN configs, but can hide malicious redirects
  • Unusual Database Entry — WordPress options containing eval and base64 together. Some plugins use this legitimately for license validation or caching

What to do: Review the file or content. If it's from a plugin you installed, it's probably fine. When in doubt, contact the plugin developer.

🔵 Notice

Informational findings that are usually harmless.

  • Complex Code Pattern — Lines over 8,000 characters that also contain eval or base64_decode. Almost always minified JavaScript from legitimate optimization. Only flagged in Thorough scan mode

What to do: Usually nothing. Use Select All and Ignore Selected to dismiss these in bulk.

Taking Action on Results

Each result has action buttons on the right side:

QuarantineMoves the file to a secure, non-executable folder. Only shown for Serious (red) threats. The safest first step — you can always restore later
DeletePermanently deletes the file from your server. Cannot be undone. Use quarantine first if you're unsure
IgnoreAdds the issue to your ignore list so it won't appear in future scans. Use for false positives you've verified as safe
Always quarantine before deleting. If deleting a file breaks something, there's no way to get it back. Quarantine gives you a safety net.

Schedule Tab

Scan Schedule

Enable automatic scansToggle scheduled scanning on/off. When off, the WordPress cron event is removed
FrequencyHourly, Daily, or Weekly. The scan runs once per interval
TimeWhat time of day to run the scan (24-hour format). Schedule during low-traffic hours like 3:00 AM
TimezoneWhich timezone the scan time is based on. Supports major US, European, Asian, and Pacific timezones plus UTC

Performance

Low resource modeMakes scans slower but uses less CPU and memory. Enable this on shared hosting if scans affect site performance
Max file size (MB)Files larger than this are skipped. Default: 5 MB. Increase if you have large PHP files from page builders
Memory limit (MB)PHP memory limit the plugin requests during scans. Default: 256 MB
Keep scan history (days)How many scan records to keep. Default: 30. Older scans are automatically removed
Auto-quarantine serious threatsWhen enabled, files flagged as Serious (red) during scheduled scans are automatically moved to quarantine

Scan Options Tab

Sensitivity

QuickFast scan of PHP files only. Good for regular checks. Catches obvious threats but skips deeper analysis
Standard (recommended)Thorough scan of all code files. Best balance of speed and detection
ThoroughDeep scan of everything. Checks more file types, looks for subtle patterns like very long code lines. May show more Notice-level results. Use this if you suspect an active infection

What to Scan

WordPress core filesScans /wp-includes/ and /wp-admin/ directories
Plugin filesScans all installed plugins in /wp-content/plugins/
Theme filesScans all installed themes in /wp-content/themes/
Uploads folderScans /wp-content/uploads/ for PHP files and disguised executables
Database contentChecks published posts and options table for injected scripts and suspicious encoded content
.htaccess fileChecks the root .htaccess for malicious server directives
All scan areas are enabled by default. Disable specific areas only if you have a good reason (like a massive uploads folder that takes too long to scan).

Email Tab

Email Recipients

Add one or more email addresses to receive scan alerts. Click + Add Email to add more addresses. Click the × to remove one. The admin email is pre-filled on first activation.

Alert Settings

Email me when issues are foundSends an alert email after any scheduled scan that detects threats. Default: On
Email me when scan is clean tooSends a confirmation email even when no issues are found. Useful if you want proof that scans are running. Default: Off
From nameThe sender name on alert emails. Default: “SSP Malware Scanner”
Send Test EmailSends a test message to all configured addresses to verify email delivery works

Email Templates

You can customize the email content for both threat and clean-scan emails separately. Use the dropdown to switch between the two template types.

For each type you can configure:

  • Subject Line — supports placeholders
  • Format — HTML or Plain Text
  • Custom HTML Template — leave blank to use the built-in default template, or paste your own HTML

Template Placeholders

{site_name}Your WordPress site name
{site_url}Your site URL
{scan_time}When the scan ran
{duration}How long the scan took (seconds)
{threats}Number of issues found
{files_scanned}Number of files checked
{threat_list}HTML-formatted list of all issues (threat emails only)
{dashboard_url}Direct link to your scanner dashboard

Exclusions Tab

Skip These Paths

Enter file paths to completely skip during scans (one per line). Use this for directories that contain many false positives or are irrelevant to security, like cache or backup folders.

Example:

  • /wp-content/cache/
  • /wp-content/backups/

Trusted Plugins

Enter plugin folder names (one per line) to skip scanning entirely. Useful for large, well-known plugins that trigger false positives due to their use of encoding or complex code.

Pre-filled defaults: woocommerce, woocommerce-subscriptions, woocommerce-square, all-in-one-seo-pack, wp-mail-smtp.

Safe Upload Paths

Subfolder names inside /uploads/ that legitimately contain PHP files. Files in these paths won't be flagged as “PHP File in Uploads.”

Folders starting with ssp- and the simple-backup-restore folder are automatically excluded and don't need to be listed here.

Ignored Issues

Shows the count of currently ignored issues. Click Clear All Ignored Issues to reset the ignore list so all previously ignored items will appear again in future scans.

Quarantine Tab

Quarantine is a safe holding area for suspicious files. When you quarantine a file:

  1. The file is moved to /wp-content/uploads/ssp-quarantine/
  2. The folder is protected with deny from all in .htaccess so files cannot be executed or accessed via the web
  3. A .meta file is created alongside it recording the original location and quarantine time
  4. The file is renamed with a timestamp and .quarantined extension

For each quarantined file you can see the original name, original path, quarantine date, and file size.

Actions

RestoreMoves the file back to its original location. The quarantine directory for the original path is recreated if it was deleted
DeletePermanently deletes the quarantined file and its metadata. Cannot be undone
Tip: Always quarantine before deleting. If removing a file breaks your site, you can restore it from quarantine. Permanent deletion has no undo.

History Tab

Shows a chronological list of all past scans, newest first. Each entry shows:

  • Date and time of the scan
  • Status: clean (green left border) or issues found (red left border) with count
  • Duration and file count

Click any history entry to expand it and see the full list of issues found during that scan. Each issue shows the same type, severity, location, and details as the Dashboard results.

Use Clear History to delete all scan records. History retention is also controlled by the Keep scan history setting in the Schedule tab.

What Gets Scanned

File Scanning

The scanner recursively walks through the directories you've enabled (core, plugins, themes) and reads each file looking for malicious code patterns. In Standard mode it checks .php, .phtml, .php5, and .pht files. In Thorough mode it checks additional file types.

Files larger than the configured max file size are skipped. The scanner's own files and quarantine folder are always excluded.

Uploads Scanning

The uploads directory gets special treatment. Instead of checking for malware patterns inside files, it checks for files that shouldn't exist in an uploads folder at all — PHP executables and files with disguised double extensions like .php.jpg.

Database Scanning

The scanner queries the wp_posts table for published posts containing <script> tags with external sources, <iframe> tags, eval(atob(...)), and document.write(unescape(...)). It also checks wp_options for entries containing both eval and base64 together.

.htaccess Scanning

Checks the root .htaccess for auto_prepend_file/auto_append_file directives and long encoded strings.

Detection Patterns

The scanner checks for these specific malware patterns in PHP files:

  • eval(base64_decode(...)) — the most common PHP malware pattern
  • eval(gzinflate(...)) and eval(gzuncompress(...)) — compressed malware payloads
  • eval(str_rot13(...)) — simple obfuscation
  • eval($_GET[...]) / eval($_POST[...]) / eval($_REQUEST[...]) / eval($_COOKIE[...]) — direct execution of user-controlled input
  • assert($_GET[...]) / assert($_POST[...]) — assert used as eval alternative
  • preg_replace with /e modifier and user input — deprecated code execution via regex
  • create_function with user input — dynamic function creation
  • file_put_contents with php://input — writing raw POST data to files
  • shell_exec, system, passthru, popen, proc_open with user input — command injection
  • Long base64 strings (500+ chars) followed by eval — obfuscated payloads
  • Nested function chains like @eval(@$a(@$b(@$c — heavily obfuscated backdoors

Performance

  • Scans run as a single AJAX request (manual) or cron job (scheduled). They don't affect frontend visitor performance
  • The plugin sets set_time_limit(0) so scans don't timeout on slow servers
  • Memory limit is configurable (default 256 MB) and set via ini_set at scan start
  • Files over the max size limit are skipped automatically
  • Low resource mode reduces processing speed to avoid overwhelming shared hosting
  • Schedule scans during off-peak hours (2:00–5:00 AM) to minimize any impact
Very large sites (10,000+ plugin/theme files) may take several minutes to scan. If scans timeout, increase the memory limit, enable low resource mode, or exclude large trusted plugin directories.

Data Storage

What's Stored

ssp_malware_optionsAll plugin settings (wp_options table)
ssp_malware_scan_historyArray of past scan results including file paths and threat details (wp_options table)
ssp_malware_ignored_threatsArray of MD5 hashes for ignored issues (wp_options table)
/uploads/ssp-quarantine/Quarantined files and their .meta files (filesystem)

External Connections

The plugin makes zero external connections. No data is sent to third-party servers. All scanning, storage, and email delivery happens on your own server using WordPress core functions (wp_mail for emails, wp_options for storage).

Recommendations by Site Type

Personal Blog or Small Site
  • Weekly scans on Standard sensitivity
  • Enable email alerts for threats only
  • Keep defaults for everything else
Business Website
  • Daily scans on Standard or Thorough sensitivity
  • Enable email alerts for both threats and clean scans (confirms scans are running)
  • Add well-known plugins to the Trusted Plugins list to reduce noise
  • Consider enabling auto-quarantine
eCommerce / WooCommerce Store
  • Daily or hourly scans — you're handling customer payment data
  • Standard sensitivity to avoid false positives from payment gateway plugins
  • Add WooCommerce and payment plugins to the Trusted Plugins list
  • Enable email alerts — you need to know immediately if something's wrong
  • Enable auto-quarantine for serious threats
Membership or High-Traffic Site
  • Enable low resource mode if scans affect site performance
  • Schedule scans during the lowest traffic hours (2:00–4:00 AM)
  • Consider hourly scans if users can upload content
  • Add legitimate upload paths to Safe Upload Paths if plugins store PHP there

Troubleshooting

Scan times out or never completes
  • Increase the Memory limit in Schedule → Performance (try 512 or 1024 MB)
  • Enable Low resource mode
  • Reduce Max file size to skip large files
  • Add large plugin directories to Trusted Plugins to skip them
  • Exclude cache and backup directories in Skip These Paths
  • Ask your host if they have a PHP execution time limit and request an increase
Too many false positives / notices
  • Switch from Thorough to Standard sensitivity — Thorough mode intentionally casts a wider net
  • Add known-safe plugins to the Trusted Plugins list
  • Use Select All + Ignore Selected to bulk-dismiss notices you've verified
  • WooCommerce, SEO plugins, and page builders often trigger notices because they use base64 encoding and long minified code — this is normal
Email alerts not being received
  • Click Send Test Email on the Email tab to verify delivery works
  • Check your spam/junk folder
  • Verify the email addresses are correct
  • Test that WordPress can send emails (install WP Mail SMTP if needed)
  • Confirm that Email me when issues are found is checked
  • Scheduled emails only fire after scheduled scans — manual scans don't send email alerts
Scheduled scans aren't running
  • WordPress cron depends on site traffic. If your site gets very little traffic, cron jobs may not fire on time
  • Consider setting up a real server cron job that hits wp-cron.php on a schedule
  • Verify Enable automatic scans is checked in the Schedule tab
  • Save the settings again — this re-registers the cron event
  • Check that no other plugin or server config is disabling wp-cron.php (check for DISABLE_WP_CRON in wp-config.php)
Quarantine failed or can't restore a file
  • Check that PHP has write permissions to /wp-content/uploads/ssp-quarantine/
  • The quarantine directory must exist — if it was deleted, deactivate and reactivate the plugin to recreate it
  • Restore requires the .meta file to know the original path. If the meta file was deleted, you'll need to move the file manually via FTP or your hosting file manager
  • File path traversal is blocked — only files within your WordPress installation can be quarantined
I found real malware. What now?
  • Don't panic. Quarantine the flagged files immediately
  • Change all WordPress admin passwords and database passwords
  • Check for any admin users you don't recognize in Users → All Users
  • Update WordPress core, all plugins, and all themes to their latest versions
  • Delete any plugins or themes you don't use
  • Run another scan after cleanup to verify everything is clean
  • If you have a clean backup from before the infection, consider restoring it
  • Contact your hosting provider — they may have additional security tools or can check server-level compromises