Search by

mage2kishan / module-malware-scanner

kishansavaliya

Active malware prevention + on-disk scanner for Magento 2. Three real-time guards (REST API, universal upload, custom-options) block PolyShell webshells, polyglot files and PHP-object-injection payloads BEFORE they touch disk. A nightly recursive scanner finds anything that slipped through, auto-qua

Package info

github.com/mage2sk/module-malware-scanner

Homepage

Type:magento2-module

pkg:composer/mage2kishan/module-malware-scanner

Statistics

Installs: 133

Dependents: 1

Suggesters: 0

Stars: 6

Open Issues: 0

1.3.3 2026-10-01 22:10 UTC

This package is auto-updated.

Last update: 2026-10-01 22:10:44 UTC


README

Panth Malware Scanner adds two layers to a Magento 2 store. A set of plugins inspects file uploads, REST and GraphQL requests, storefront request URIs and cart custom-option payloads while a request is being processed, and rejects anything that matches a built-in list of indicators (PHP open tags, known webshell names and hashes, polyglot image files, StyleSmuggler request markers). Inside files with valid image magic bytes a bare <?= byte sequence is ignored unless printable code follows it, so compressed photo data does not trigger a false positive. A signature-based scanner then walks the configured directories on disk, records every file that matches a signature in an admin grid, optionally moves critical findings inside upload directories to a quarantine folder, and emails a summary of new findings.

The module is used by store owners, agencies and developers who want blocked requests and on-disk findings visible inside the Magento admin. Its own user guide states that it is one layer of a defence-in-depth setup and is not a substitute for security patches, web application firewalls, backups or security audits.

Product page: kishansavaliya.com/magento-2-malware-scanner.html

Scan Findings grid

Features

  • Eleven guard plugins registered through etc/di.xml, etc/frontend/di.xml, etc/graphql/di.xml and etc/webapi_rest/di.xml (see the guard table under Usage).
  • On-disk scanner with filename, pathglob, hash, literal and regex signature types; signatures cover PolyShell webshells, polyglot image files, eval(base64_decode( style backdoors, .htaccess PHP handlers, StyleSmuggler markers, implant names and SHA-256 hashes, command-and-control domains and addresses, and INSERT INTO admin_user statements.
  • Built-in path allowlist for known dev and test packages (PHPUnit, PHPStan, Rector, PHP_CodeSniffer, Symfony polyfills, vendor/composer/, dev/tests/ and others) plus an admin-configurable list of extra allowlist paths.
  • Auto-quarantine of critical findings inside configured quarantine zones; the file is copied to var/panth_malware_quarantine/ with a .quarantined suffix, set to mode 0600 and the original is removed. Files outside the zones are only reported.
  • Scan Findings grid with severity, file path, matched signatures, status, size, first seen and last seen; row actions View File, Quarantine & Delete and Mark Ignored; mass actions Quarantine & Delete, Delete Permanently and Mark as Ignored; Run Scan Now button.
  • Blocked Requests grid with time, request type, source IP, request URI, method, matched signature, severity and user agent (method and user agent hidden by default, available under Columns); a detail page per record; Clear Old Records button.
  • Scheduled scan on a configurable cron expression, console command bin/magento panth:malware:scan, and an in-admin Documentation & Hardening Guide page.
  • Email notification for new findings at or above a configurable severity, sent with the template "Panth Malware Scanner: New Findings".
  • Extension allowlist for customer-facing uploads and an optional hourly cron that deletes files with non-allowlisted extensions from customer upload directories.
  • Extra command-and-control domains and attacker addresses can be added in the admin without a module update.
  • Unit tests under Test/Unit/ for the detectors, scanner evaluation and reconciliation, notifier, signature provider and GraphQL guards.

Compatibility

Platform Versions
Magento Open Source 2.4.4 to 2.4.8
Adobe Commerce 2.4.4 to 2.4.8
PHP 8.1, 8.2, 8.3, 8.4

Composer constraints: magento/framework ^103.0, magento/module-backend ^102.0, magento/module-ui ^101.2, magento/module-cron ^100.4, magento/module-config ^101.2, magento/module-store ^101.1, magento/module-catalog ^104.0, magento/module-webapi ^100.4.

Requirements

  • Magento Open Source or Adobe Commerce 2.4.4 to 2.4.8.
  • PHP ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0.
  • mage2kishan/module-core ^1.0 (module Panth_Core), which provides the parent admin menu and is loaded before this module.
  • The magento/* packages listed above.
  • PHP mbstring extension (mb_substr is used when building finding snippets) and a working Magento cron for scheduled scans. No external binaries are called.

Installation

composer require mage2kishan/module-malware-scanner
bin/magento module:enable Panth_Core Panth_MalwareScanner
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

setup:di:compile is only needed in production mode. The static content step is required because the module ships view/adminhtml/web/css/scan-grid.css.

Check the result:

bin/magento module:status Panth_MalwareScanner

Configuration

Admin path: Stores > Configuration > Panth Extensions > Malware Scanner. All settings are in the default scope except where noted. The section is protected by the ACL resource Panth_MalwareScanner::system_config.

Admin configuration

General

Setting Default What it does
Enable Module Yes Turns the on-disk scanner, the cron scan, the upload janitor cron and every guard plugin on or off. When it is No, all guards let requests through unchanged. If the setting cannot be read, the guards stay active.
Max File Size to Scan (KB) 2048 Files larger than this are skipped by the scanner.
Scan Paths (relative to Magento root) pub/media, app/code, vendor, var, generated, lib, bin, setup, pub/static Directories the scanner walks, one per line.
Exclude Paths var/cache, var/log, var/page_cache, var/session, var/tmp, var/view_preprocessed, var/composer_home, generated/code, generated/metadata, pub/static/_cache, pub/static/frontend, pub/static/adminhtml, pub/media/catalog/product/cache Directories skipped by the scanner, one per line. var/panth_malware_quarantine and the module's own directory are always excluded.
File Extensions to Scan php,phtml,phar,php3,php4,php5,php7,phps,inc,htaccess,jpg,jpeg,png,gif,svg,html,htm,js Comma-separated list. .htaccess files are always included.
Enforce Extension Allowlist on Customer Uploads Yes Customer file uploads (customer and customer address attributes, frontend upload controllers) are rejected when the extension is not on the allowlist, regardless of content. Website and store view scope.
Customer Upload Extension Allowlist jpg,jpeg,png,gif,webp,bmp,pdf,doc,docx,xls,xlsx Comma-separated. Shown only when the setting above is Yes. Website and store view scope.

Scheduled Scan

Setting Default What it does
Enable Cron Scan Yes Runs the scanner from the panth_malwarescanner_run cron job. Requires Enable Module = Yes.
Cron Expression 0 3 * * * Schedule of the cron job (daily at 03:00 by default).

Active Protection

Setting Default What it does
Auto-Quarantine Critical Findings Yes During a scan, files with a critical signature match inside a quarantine zone are moved to var/panth_malware_quarantine/.
Report Only (Dry Run) No When Yes, scans record findings but never move files; critical findings inside the quarantine zones are only logged as "would quarantine". Applies to the cron scan, Run Scan Now and the console command.
Quarantine Zones pub/media, var/import, var/export, var/tmp, var/importexport Directories where auto-quarantine may remove files. app, app/code, app/design, app/etc, vendor, lib, generated, bin, setup, pub/static, pub/errors and dev are ignored even if entered here.
Purge Non-Allowlisted Customer Uploads (read-side janitor) No Enables the hourly panth_malwarescanner_purge_uploads cron job, which deletes files under pub/media/customer_address, pub/media/customer and pub/media/custom_options whose extension is not on the Customer Upload Extension Allowlist. Each deletion is logged to the Blocked Requests grid as janitor_purge.
Block Payment Mutations For Disabled Methods Yes Rejects the GraphQL mutations handlePayflowProResponse, createPayflowProToken, getPayflowLinkToken, createPaypalExpressToken and createBraintreeClientToken with HTTP 400 when none of the related payment methods is active for the current store. Website and store view scope.
Extra Allowlist Paths (empty) Path prefixes, one per line, skipped by the scanner in addition to the built-in allowlist.

Active Protections

A read-only group of label fields listing the guard plugins (Upload Guard, REST API Guard, GraphQL Guard, Payment Mutation Guard, Custom Option Guard, Media Path Guard, Frontend Path Guard, Customer File Guard, Customer Attribute Guard, Image Content Guard, Webapi File Guard, Cart Custom Option Guard). It has no settings.

Threat Indicators

Setting Default What it does
Extra command-and-control domains (empty) Hosts, one per line or comma separated, added to the shipped list. A file containing one raises a critical finding.
Extra attacker addresses (empty) IP addresses added to the shipped list. Matched only in script files and under pub/media, var/report, var/import, var/export and var/importexport; a match raises a high finding.

Email Notifications

Setting Default What it does
Send Email on Detection Yes Sends the findings email after a scan. Nothing is sent while Recipient Emails is empty.
Recipient Emails (empty) One address per line.
Minimum Severity for Email High Findings below this severity are not emailed.
Sender General Contact Store email identity used as the sender.

Config paths: panth_malwarescanner/general/enabled, panth_malwarescanner/general/max_file_size_kb, panth_malwarescanner/general/scan_paths, panth_malwarescanner/general/exclude_paths, panth_malwarescanner/general/extensions, panth_malwarescanner/general/enforce_upload_extension_allowlist, panth_malwarescanner/general/upload_extension_allowlist, panth_malwarescanner/cron/enabled, panth_malwarescanner/cron/schedule, panth_malwarescanner/protection/auto_quarantine, panth_malwarescanner/protection/dry_run, panth_malwarescanner/protection/quarantine_zones, panth_malwarescanner/protection/purge_nonallowlisted_uploads, panth_malwarescanner/protection/payment_method_guard, panth_malwarescanner/protection/allowlist_paths, panth_malwarescanner/indicators/extra_c2_domains, panth_malwarescanner/indicators/extra_c2_ips, panth_malwarescanner/notification/enabled, panth_malwarescanner/notification/recipients, panth_malwarescanner/notification/min_severity, panth_malwarescanner/notification/sender.

Admin menu: the module adds a "Malware Scanner" group under the Panth_Core menu with the entries "Scan Findings", "Blocked Requests", "Configuration" and "Documentation & Hardening Guide". With default settings the scanner runs nightly, auto-quarantine is on, the upload janitor is off and no email is sent until recipients are entered.

Usage

Request guards

The guards run inside the request. A blocked upload raises a LocalizedException and the temporary file is deleted; a blocked REST request gets HTTP 400; a blocked GraphQL request gets HTTP 400 (entry guard, payment guard) or a GraphQlInputException (query guard); a blocked storefront URI or media path gets an empty HTTP 404. Every block is written to the panth_malware_blocked_request table with source IP, user agent, URI, method, matched indicator, SHA-256 of the payload and a 500-character excerpt. Internal errors while inspecting a request let the request continue; an error while logging a block does not cancel the block.

Guard Hooks What it checks
Upload Guard Magento\Framework\File\Uploader::save First 64 KB of uploads with PHP, script, HTML, SVG, .htaccess or image extensions: image header followed by a PHP tag, or any inline needle (PHP tags, PolyShell beacons and hashes, eval(base64_decode, system($_REQUEST and similar).
REST API Guard Magento\Webapi\Controller\Rest::dispatch URI, query string and header names for injected code, x_trace_ markers and the X-TRACE-<hex> header; POST, PUT and PATCH bodies up to 2 MB for inline needles and base64-encoded PHP tags. Token, customer, payment-information and order endpoints are skipped for the body check.
GraphQL Entry Guard Magento\GraphQl\Controller\GraphQl::dispatch Header names, any styles[ query parameter and injected code in the URI (decoded up to three times).
GraphQL Guard Magento\Framework\GraphQl\Query\QueryProcessor::process Mutation source text and variables for inline needles and base64 needles.
Payment Mutation Guard Magento\GraphQl\Controller\GraphQl::dispatch Payment mutations whose payment methods are all inactive for the current store (configurable).
Custom Option Guard Magento\Catalog\Model\Product\Option\Type\File\ValidatorFile::validate Product custom-option file uploads: image header followed by a PHP tag, or any inline needle in the first 64 KB.
Cart Custom Option Guard Magento\Catalog\Model\CustomOptions\CustomOptionProcessor::convertToBuyRequest file_content, file_data, base64_encoded_data and content values on cart items, raw and base64-decoded.
Customer File Guard Magento\Customer\Model\FileProcessor saveTemporaryFile and moveTemporaryFile for customer and customer address files, including the extension allowlist.
Customer Attribute Guard Magento\Framework\App\Action\Action::execute (frontend) Upload-shaped frontend controllers, including the extension allowlist.
Image Content Guard Magento\Catalog\Model\ImageUploader::saveFileToTmpDir Admin catalog image uploads: known shell names, missing extension, extension outside jpg, jpeg, gif, png, webp and svg, image header followed by a PHP tag, or any inline needle.
Media Path Guard Magento\MediaStorage\App\Media::launch (pub/get.php) Executable extensions, missing extensions and known shell names inside customer-writable media directories.
Frontend Path Guard Magento\Framework\App\FrontController::dispatch (frontend) Known PolyShell paths, known shell file names and injected code in the request URI.
Webapi File Guard Magento\Framework\Api\Uploader (webapi_rest) REST service-contract file uploads: known shell names, executable extensions, or any inline needle.

On-disk scan

A scan walks each configured scan path, skipping excluded and allowlisted paths, symlinked files, symlinked directories (they are not followed; a configured scan path that is itself a symlink is still opened), files with other extensions and files above the size limit. Each file is read in full, hashed with SHA-256 and evaluated against every signature. A match is stored in panth_malware_scan_result with the highest severity, the matched signature IDs, a 400-character snippet and the first and last seen timestamps. An existing row is reset to status new when the file hash changes. After a complete scan, open findings whose file is gone are set to clean and findings whose path is no longer scanned are set to excluded.

Run a scan in one of three ways:

  • Admin: Scan Findings > Run Scan Now (ACL Panth_MalwareScanner::scan_run). The button asks for confirmation and sends a POST request with the admin form key; the panth_malwarescanner/scan/run controller rejects GET requests. The controller allows up to 900 seconds and sends the notification email afterwards.
  • Cron: job panth_malwarescanner_run on the configured expression (default 0 3 * * *); the result, including dry_run and would_quarantine, is written to the Magento log.
  • Console: bin/magento panth:malware:scan, with the option --no-email to skip the notification and --dry-run to report findings without quarantining any file for that run. Progress is printed every 200 files.

Report Only (Dry Run), panth_malwarescanner/protection/dry_run, default No: when set to Yes, every scan (cron, Run Scan Now and the console command) records findings as usual but never moves a file. Files that would have been auto-quarantined are counted as would_quarantine and logged with the message DRY RUN: would quarantine <path>. With the default No, Auto-Quarantine behaves as before.

Reviewing findings

Findings have the statuses New, Reviewed, Ignored / False Positive, Quarantined, Deleted, Clean (file no longer on disk) and Excluded (path no longer scanned). From the grid you can view the first 512 KB of a file (ACL Panth_MalwareScanner::scan_view_file), quarantine it, delete it permanently or mark it ignored. Quarantine, Delete Permanently and Mark Ignored require Panth_MalwareScanner::scan_delete. Quarantine copies the file to var/panth_malware_quarantine/<timestamp>__<sanitised path>.quarantined (a numeric suffix is added if that name exists) and removes the original; Delete Permanently unlinks the file. Both actions refuse symlinks and paths outside the Magento root. Ignored, deleted, clean and excluded findings are not emailed again.

Blocked Requests grid

Alert emails

After a scan, findings with notified = 0, a status that is not resolved and a severity at or above Minimum Severity for Email are sent in one message with the subject "Malware Scanner Alert: N new finding(s) on " and a table of severity, file path, signatures and first seen. Findings whose file has disappeared in the meantime are left out of the email and keep their status; the next complete scan marks them clean. The email is sent only when Send Email on Detection is Yes and at least one valid recipient is configured. Blocked requests do not trigger emails.

Data retention

Scan findings are kept until they are deleted from the grid. Blocked request records are kept until an administrator uses Clear Old Records on the Blocked Requests grid, which asks for confirmation and sends a POST request with the admin form key (GET requests are rejected); it deletes records older than 90 days by default (the days parameter accepts 1 to 3650). Quarantined files stay in var/panth_malware_quarantine/ until removed manually.

Developer Notes

  • Module name: Panth_MalwareScanner; Composer package: mage2kishan/module-malware-scanner; namespace: Panth\MalwareScanner.
  • Signatures, inline needles, base64 needles, implant hashes and the built-in allowlist live in Model\SignatureProvider. Request-side patterns live in Model\AttackPatternDetector and Model\RequestInjectionDetector. Model\Scanner evaluates files, Model\FileAccess performs quarantine, purge and safe reads, Model\Notifier sends the email, Model\BlockedRequestLogger writes blocked-request rows, and Helper\Config exposes every setting.
  • The payment guard's operation-to-method map is the guardedOperations argument of Plugin\GraphQl\PaymentMethodGuard in etc/graphql/di.xml and can be extended from another module's di.xml.
  • Console command: Console\Command\ScanCommand (panth:malware:scan). Cron classes: Cron\RunScan, Cron\PurgeNonAllowlistedUploads.
  • Admin route panth_malwarescanner; controllers under Controller\Adminhtml\Scan (Index, Run, View, Delete, Purge, Ignore, MassDelete, MassPurge, MassIgnore), Controller\Adminhtml\BlockedRequest (Index, View, Clear) and Controller\Adminhtml\Docs\Index.
  • UI components: panth_malware_scan_listing and panth_malware_blocked_listing.
  • ACL resources: Panth_MalwareScanner::malware, ::scan_view, ::scan_run, ::scan_delete, ::scan_view_file, ::blocked_log, ::config, ::system_config.
  • Database tables (etc/db_schema.xml): panth_malware_scan_result and panth_malware_blocked_request.
  • Email template: panth_malwarescanner_notification_template (view/frontend/email/malware_alert.html).

Uninstallation

bin/magento module:disable Panth_MalwareScanner
composer remove mage2kishan/module-malware-scanner
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

The tables panth_malware_scan_result and panth_malware_blocked_request, the panth_malwarescanner/* rows in core_config_data and any files in var/panth_malware_quarantine/ are not removed by these commands. Panth_Core stays installed if other Panth modules use it.

Support

Documentation

USER_GUIDE.md covers installation, verifying the guards, each configuration screen, the scheduled scan, email notifications, the findings grid and quarantine workflow, severity levels, the in-admin documentation page, the customer upload allowlist with the matching nginx rules, StyleSmuggler checks, troubleshooting and a CLI reference.

License

Commercial software license. See LICENSE.txt in this repository.

Changelog

See CHANGELOG.md.

Links