Module guide Kowal_SecurityScan
Overview
The module extends Magento 2 with a security monitoring layer for application files, selected database tables, suspicious URLs, and optional incident analysis by OpenAI.
Reports are stored in the kowal_securityscan_report table and can be sent by email.
Main features
- Magento file change scan with comparison to a snapshot,
- heuristic scan of
php,phtml,php5,inc,phar,js,html,htm,svg,htaccessfiles, - PHP token analysis via
token_get_all(), - scan of selected database tables for malicious HTML, JavaScript, SVG,
data:URI, and suspicious URLs, - integration with Google Safe Browsing API,
- optional OpenAI analysis for detections,
- configurable allowlists for domains, files, content patterns, and rules,
- reports with ready-to-use allowlist suggestions and normalized JSON configuration export.
Requirements
- Magento 2,
- available
kowal/basemodule, - working Magento cron,
- properly configured email sending,
- optional: OpenAI API key and Google Safe Browsing API key.
Installation
1. Add the package repository
If the package is not available in the default Composer repository, add the source:
composer config repositories.securityscan vcs https://github.com/kowalco/module-securityscan
If the repository requires authorization:
composer config --global --auth github-oauth.github.com
2. Install the package
composer require kowal/module-securityscan
3. Enable the module
php bin/magento module:enable Kowal_SecurityScanphp bin/magento setup:upgradephp bin/magento cache:flush
In a production environment, perform the standard Magento deployment steps according to your deployment process.
Cron and scan schedule
The module registers its own cron group securityscan.
kowal_securityscan_filecheck- daily at00:00,kowal_securityscan_malwarecheck- daily at01:00,kowal_securityscan_dbcheck- daily at02:00,kowal_securityscan_cleanup_reports- daily at02:30.
Without a working Magento cron, automatic scans will not run.
Manual scan execution
To run scans manually, use:
php bin/magento kowal_securityscan:filecheckphp bin/magento kowal_securityscan:malwarecheckphp bin/magento kowal_securityscan:dbcheck
This is the recommended testing method after installation and after configuration changes.
Configuration
Configuration path:
Stores -> Configuration -> kowal -> kowal_security
General settings
Enable moduleReport recipient email addressSender email addressReport retention in daysGoogle Safe Browsing API KeyDomain allowlistFile allowlistDatabase pattern allowlistFile rule allowlistDatabase rule allowlist
Minimum configuration
- enable the module,
- set the report recipient address,
- set the report sender address,
- make sure Magento email sending works,
- make sure Magento cron works.
OpenAI analysis
The OpenAI Analysis section lets you extend reports with risk assessment and recommended actions.
Available fields:
Enable AI analysis,OpenAI API Key,OpenAI Model,Maximum context for AI.
How to enable
- enable
Enable AI analysis, - fill in
OpenAI API Key, - save configuration,
- refresh the configuration form,
- select the model.
Default behavior
- default model:
gpt-4.1-mini, - default context limit:
12000, - values below
2000are raised to12000, - maximum context limit is
50000.
If OpenAI is disabled or the key is missing, the module still works and uses local heuristics.
Google Safe Browsing
If you fill in the Google Safe Browsing API Key, the module will:
- check URLs detected in files and the database,
- check the store base URL.
Missing a key does not block basic scans, it only disables this stage.
File change scan
filecheck works based on a snapshot saved to:
var/security_scan_hashes.json
On the first run:
- a snapshot is created,
- there is no change comparison yet,
- the report informs about creating the reference baseline.
Subsequent runs report changes of type ADDED, MODIFIED, and REMOVED.
The following are skipped, among others:
var/,generated/,vendor/,pub/static/,node_modules/.
File malware scan
malwarecheck scans application files based on:
- regex rules with
rule_id, - PHP token heuristics,
- URL checks via Safe Browsing.
Example detection types:
file.obfuscated_eval_chain,file.command_execution_from_request,file.encoded_payload_blob,file.token.decode_execute_chain,file.token.include_from_request,file.inline_svg_or_event_handler.
In reports, reasons are presented in the format:
[file.encoded_payload_blob] Encoded payload blob detected
Database scan
dbcheck analyzes selected Magento tables:
cms_block,cms_page,core_config_data,email_template,newsletter_template,review_detail,catalog_product_entity_text.
Example rules:
db.inline_script_tag,db.html_event_handler,db.external_iframe,db.javascript_uri,db.data_uri_executable,db.embedded_svg_payload,db.javascript_dom_redirect.
Content is normalized beforehand using:
html_entity_decode,rawurldecode,- whitespace normalization,
- analysis of multiple variants of the same content.
Advanced configuration: allowlists
Allowlists are used to reduce false positives without disabling the entire module.
1. Domain allowlist
Field: kowal_security/general/allowlisted_domains
Format:
- one domain per line, or
- a comma-separated list.
cdn.example.comstatic.example.org
Effect:
- URLs from these domains will not be treated as suspicious,
- Safe Browsing will not check them.
2. File allowlist
Field: kowal_security/general/allowlisted_file_patterns
Format:
- relative paths,
- glob support.
app/code/Vendor/Module/Test/*pub/media/custom.js
Effect: files matching the pattern are completely skipped by the malware scan. This setting has a broad scope.
3. Database pattern allowlist
Field: kowal_security/general/allowlisted_db_patterns
Format:
- phrases,
- HTML or JS fragments,
- entries separated by a new line or commas.
trusted-inline-widgetdata:image/svg+xml
Effect: a database record containing such a fragment is skipped by the DB scan. This setting also has a broad
scope.
4. File rule allowlist
Field: kowal_security/general/allowlisted_file_rules
Preferred format:
path_or_glob | rule_id
Example:
app/code/Vendor/Module/* | file.encoded_payload_blobpub/media/custom.js | file.javascript_redirect_or_rewrite
Backward compatibility:
- old entries by full rule label still work,
- new entries should use
rule_id.
Effect: only the specified rule is silenced for the specified path, while the rest of the scan for that file
still works.
5. Database rule allowlist
Field: kowal_security/general/allowlisted_db_rules
Preferred format:
table_or_* | rule_id
Example:
cms_block | db.inline_script_tag* | db.fetch_or_xhr_loader
Effect: only the specified rule is silenced, while the others still work for that record or table.
Reports
Reports may contain:
- a list of detections,
- risk assessment,
- indicators and recommendations,
- allowlist candidates after manual verification,
- normalized allowlist configuration in JSON.
Allowlist suggestions in reports
The report section may contain entries such as:
- cms_block | db.inline_script_tag | confidence=MEDIUM | scope=LOW- app/code/Vendor/Module/* | file.encoded_payload_blob | confidence=MEDIUM | scope=LOW- data:image/svg+xml,
Interpretation:
scope=LOW - safer candidate,
scope=HIGH - broad silencing, only after strict verification,
confidence=MEDIUM/HIGH - more predictable configuration candidate,
confidence=LOW - requires caution.
JSON export
The report also contains the Normalized allowlist configuration (JSON) section. This is a ready,
deduplicated set of values to copy into the configuration.
Recommended usage flow
- run all three scans manually after installation,
- treat the first
filecheck as snapshot creation,
- analyze reports and confirm which detections are real,
- for false positives, first use
allowlisted_file_rules and allowlisted_db_rules,
- only when necessary, use
allowlisted_domains, allowlisted_file_patterns, and
allowlisted_db_patterns,
- after changing configuration, rerun the appropriate CLI scan and check the result.
Operational notes
filecheck does not yet report changes as an incident on the first run,
- the module works without OpenAI and without Safe Browsing, but with lower analysis depth,
allowlisted_file_patterns and allowlisted_db_patterns have broad impact and
should be used sparingly,
- the preferred format for rule allowlists is
rule_id, not the full text label.























