Search by

marcocesarato / amwscan

marcocesarato

AMWSCAN (Antimalware Scanner) is a php antimalware/antivirus scanner console script written in php for scan your project. This can work on php projects and a lot of others platform.

Package info

github.com/marcocesarato/PHP-Antimalware-Scanner

Type:console

pkg:composer/marcocesarato/amwscan

Statistics

Installs: 22 004

Dependents: 1

Suggesters: 0

Stars: 788

Open Issues: 5

0.21.10 2026-09-13 12:08 UTC

This package is auto-updated.

Last update: 2026-09-13 12:19:26 UTC


README

PHP Antimalware Scanner logo

PHP Antimalware Scanner

Scan PHP projects and WordPress installations for suspicious code, integrity changes, and known malware patterns.

Version PHP License Documentation

Documentation | Latest release | Docker Hub | GitHub Action | WordPress.org plugin

Documentation is available in English, Italian, German, French, Spanish, Russian, Simplified Chinese, Japanese, Hindi, and Arabic. Use the language selector in the documentation navigation.

Start with a safe report

Download the standalone scanner, confirm its version, then inspect a project without changing files:

curl --fail --silent --show-error --location \
  --output scanner \
  https://raw.githubusercontent.com/marcocesarato/PHP-Antimalware-Scanner/master/dist/scanner

php scanner --version
php scanner /var/www/example --lite --report-only

The scanner writes scanner-report.html in the current directory. Review each finding in context before cleaning, quarantining, or deleting anything.

Caution

Create a current backup before using file actions. A detection identifies suspicious code. It does not prove that the entire file is malicious.

Interactive CLI

PHP Antimalware Scanner interactive CLI showing scan progress and detected threats

What it checks

Check Purpose
Malware signatures Finds known code fragments, regular expressions, hashes, and suspicious domains
JavaScript Applies scoped JavaScript malware definitions and dangerous-domain checks to .js files by default
Exploit patterns Flags code structures that attackers often use
Framework processes Associates confirmed process APIs from major PHP frameworks and platforms with their owner
Dangerous functions Identifies calls such as system and shell_exec for review
Platform integrity Compares supported applications and packages with trusted release checksums
ZIP archives Inspects bounded archive content when --scan-archives is enabled
WordPress database Inspects triggers, administrators, and orphaned posts, with confirmed local remediation

Framework process findings run in Full, Lite, Exploits, and Functions modes, but not Signatures-only mode. They use PHP token analysis and require both exact framework provenance and a terminal execution method. Coverage includes Symfony Process, legacy ProcessBuilder, and process-message dispatch; Laravel Process; WordPress SSH and WP-CLI; Magento / Adobe Commerce; Drupal / Drush; Joomla; PrestaShop; TYPO3; CodeIgniter; Yii; and CakePHP. A generic Process class, a bare run() or execute() call, and framework constructors or builders without execution are not reported. WooCommerce has no verified product-owned operating-system process API, so its WordPress and WP-CLI paths remain covered while in-process Action Scheduler work is excluded. Ordinary confirmed execution remains warning-level review evidence. A command literal connected to that execution is promoted to dangerous only for high-confidence behavior such as download-to-interpreter pipelines, encoded interpreter execution, reverse shells, or destructive root deletion.

Normal code scans work offline with embedded definitions. Platform checksums and Maltrail definition updates can require outbound HTTPS. Dedicated integrity verifiers cover WordPress, WooCommerce, Drupal, Joomla, Magento / Adobe Commerce, PrestaShop, TYPO3, Laravel, Symfony, CodeIgniter, Yii, and CakePHP. Framework verifiers validate only their owned locked Composer packages against official distributions; WooCommerce uses official WordPress plugin checksums. Successful remote data is cached outside the scanned project; failed WordPress checksum requests are retried after one hour. Integrity manifest paths remain anchored to the detected installation root, including when a root directory name is repeated in a managed filename. When every eligible file passes checksum verification, AMWScan also skips supplemental component-inventory and reputation checks.

Choose a mode

Mode Option Use it when
Full No mode option You need the broadest incident review
Lite --lite, -l You want a practical first scan that omits noisy shell-output signatures
Signatures --only-signatures, -s You want focused checks for known malware patterns
Exploits --only-exploits, -e You want to audit suspicious code structures
Functions --only-functions, -f You want to review dangerous PHP calls

Read Run your first scan for guidance on reviewing and acting on findings.

Reduce false positives

Full and Lite scans distinguish short quoted paths from long obfuscated strings, and exclude binary data inside PHP strings and comments from the non_printable heuristic. This avoids false positives in PDF and cryptography libraries without trusting files by their path. Rescan after updating to replace earlier findings.

Full and Lite scans detect request-driven Base64 data: and data:// includes, including concatenated and interpolated request values. Plain URI assignments, static Base64 text, and literal variable names in single-quoted strings do not trigger the base64_inclusion rule. Decoding preserves heredoc and nowdoc line breaks so PHP context checks continue to recognize documentation strings.

In Lite mode only, alignment, long concatenations, encoded function names (hex_char), escaped include paths, and loader/reconnaissance proximity heuristics produce informational exploit-candidate findings instead of marking a file infected. The execution rule also treats decoded callback names as candidates unless the matched callback argument contains executable request input or directly decodes a known dangerous function name with Base64 or ROT13. Candidates remain in reports and qualify for optional advisory AI review; alone, they do not trigger remediation or a nonzero exit code. Independent execution detections and specific signatures retain their severity, so corroborating findings can still mark the file infected. Full mode keeps its existing behavior.

Lite adds PHP-context checks for request-driven file writes and sensitive-file reads, and distinguishes request-controlled backtick commands from quoted examples and escaped dollar signs. Proximity alone does not prove a data-flow connection; review candidates for indirect decoding and execution.

Start with --lite --report-only and review the matched code before taking action. Bare generic keyword matches such as backdoor appear as informational keyword findings; they do not mark a file as infected or cause a nonzero CLI exit code. Substrings inside longer words do not produce these advisories.

Standalone encoded names such as lave remain visible as informational encoded-function-candidate findings, including in assignments and array keys; color names such as lavender do not qualify. An exact encoded name in a corresponding PHP decoder call, such as strrev('lave'), remains a detection. When enabled, AI review can assess both keyword and encoded-name candidates without changing their status or triggering remediation. Function checks and execution-oriented exploit rules use PHP tokens to reject matches in comments, quoted examples, HTML, and unrelated method names. Specific malware signatures and non-PHP rules still examine file text, so a complete malware example in documentation can still need review.

Use --ignore-exploits=<name> to exclude a reviewed exploit rule for a scan, or whitelist an individual reviewed finding. Excluding a rule reduces coverage; avoid broad directory exclusions for writable application code.

Reuse reviewed findings

Use --auto-whitelist only after confirming that every reported finding is safe. JSON whitelist entries use exact paths relative to the scan root, compare stored match content, and retain file-level findings whose line is null. Legacy CSV files do not store match content and represent these findings with an empty line column. New CSV files include a version marker that distinguishes absolute paths from historical leading-separator relative paths. --whitelist-only-path ignores line numbers but still requires the same path and detection; JSON entries also require the same stored match.

php scanner /var/www/example --auto-whitelist \
  --path-whitelist=/var/lib/amwscan/example-whitelist.json

Keep whitelist files outside the public document root and reuse the same scan root on later scans.

GenAI-assisted finding review

AMWScan can ask an AI provider whether each detected code fragment is likely malware, a false positive, or uncertain. Reviews run after detection, include a bounded excerpt around the matched line, and are advisory only: they never clean, delete, quarantine, whitelist, or change a finding status automatically.

AI review is disabled by default. Enable one provider with --ai-provider.

API providers

Provider Option API key environment variable
OpenAI --ai-provider=openai OPENAI_API_KEY
Anthropic --ai-provider=anthropic ANTHROPIC_API_KEY
Google Gemini --ai-provider=gemini GEMINI_API_KEY

AMWSCAN_AI_API_KEY can be used as a provider-independent override. API keys are not accepted as command arguments, which prevents them from appearing in shell history and process listings. The WordPress plugin provides a protected API key field and retrieves the available model list directly from the selected provider. Google AI Studio's limited free Gemini tier is the recommended starting option.

On WordPress 7.0 or newer, sites with the WordPress AI Client can select WordPress AI / configured connectors instead. AMWScan then uses wp_ai_client_prompt() and the credentials, dynamic compatible-model registry, fallback, and connector approval policy managed under Settings → Connectors. Automatic selection uses WordPress AI's filterable preferred-model list. This integration is capability-detected and is not a required plugin dependency.

Installed CLI providers

CLI Option Default command
Claude Code --ai-provider=claude-code-cli claude
OpenAI Codex --ai-provider=codex-cli codex
GitHub Copilot --ai-provider=copilot-cli copilot
OpenCode --ai-provider=opencode-cli opencode

Installed CLIs run in an empty private working directory with tools and project instructions restricted where supported. Claude Code and Codex receive source through standard input; Copilot and OpenCode receive it through a private temporary file so source does not appear in the process argument list. These CLIs normally send the supplied code to remote model services; "installed" does not mean data stays on this machine. Use --ai-executable=<path> to select another executable and --ai-model=<model> to override its model.

# API provider
GEMINI_API_KEY=your-key php scanner /path/to/project --report-only \
  --ai-provider=gemini --ai-context-lines=5 --ai-max-findings=20

# Installed local CLI
php scanner /path/to/project --report-only \
  --ai-provider=claude-code-cli --ai-model=claude-sonnet-4-5

Direct API defaults are gpt-5.6-luna, claude-haiku-4-5, and gemini-3.8-flash. AI verdicts, model confidence, provider status, and schema version are included in CLI output and structured reports. See the CLI reference for timeout, context, model, and review-limit options.

Install

Standalone release

Download scanner from the latest release, then run it with PHP:

php scanner /path/to/project --lite --report-only

Composer project dependency

composer require marcocesarato/amwscan
php vendor/bin/amwscan /path/to/project --lite --report-only

Docker Hub

The image uses PHP 8.5 on Alpine, refreshes Alpine packages during release builds, and omits the unused curl command while retaining PHP's curl extension. See the container guide for local builds and security-update details.

Use the marcocesarato/php-antimalware-scanner Docker image from Docker Hub:

docker pull marcocesarato/php-antimalware-scanner:latest
docker run --rm \
  --volume "/path/to/project:/scan:ro" \
  --volume "$PWD/amwscan-output:/output" \
  marcocesarato/php-antimalware-scanner:latest /scan \
  --lite --report-only --report-format=html \
  --path-report=/output/report.html \
  --disable-checksum --disable-definitions-update

PHP 7.4 or newer is required. The required extensions are fileinfo, json, mbstring, phar, and zlib. Read the installation guide for global Composer, source, Docker, Windows, and WordPress instructions.

Reports for people and tools

# Interactive review with a stored report
php scanner /path/to/project --lite --report --report-format=html

# Structured automation without prompts
php scanner /path/to/project --lite --report-only --report-format=json

# Code scanning tools without prompts
php scanner /path/to/project --lite --report-only --report-format=sarif

# Spread large report-only scans across several CPU cores
php scanner /path/to/project --lite --report-only --jobs 4

Report-only scans use up to 8 parallel worker processes by default when the pcntl extension and its required process-control functions are enabled. Pass --jobs auto (or --jobs 0) to use every detected CPU core, --jobs N to set a fixed count, or set AMWSCAN_JOBS to configure the default. Parallelism only applies to local, non-interactive report-only scans; interactive scans, FTP sources, programmatic scans with active output buffers, and PHP configurations that disable the required functions run sequentially. Resumable checkpoint scans remain eligible for parallel workers; the parent process persists completed worker chunks and merges them in scan order, so an interrupted run retains out-of-order completed work without skipping unfinished files. Pass --jobs 1 to force a single process. Worker processes start at the lowest CPU priority by default so a scan never starves interactive or system processes; set the AMWSCAN_WORKER_PRIORITY environment variable (niceness -20..19) to override.

Available formats are HTML, text, JSON, and SARIF. HTML reports place malware first at full width and organize other detected issues—such as integrity changes, database findings, large files, reputation warnings, and suspicious hashes—into conditional collapsible panels ordered by severity. They also support system-aware light and dark modes, text, severity, and category filters, and ten selectable interface languages, including right-to-left Arabic. Empty categories and their filter choices are omitted. Reports include coverage totals and skipped file reasons, so incomplete scans do not look clean.

HTML report generated from scanner fixtures, showing scan totals and detected findings

CI/CD

Run a non-destructive Lite scan with the GitHub Marketplace action:

- name: Check out repository
  uses: actions/checkout@v4

- name: Scan for malware
  uses: marcocesarato/PHP-Antimalware-Scanner@v0.19.2
  with:
    path: .
    mode: lite
    report-format: sarif

The action returns exit code 1 when it finds a security issue and 2 when the scanner cannot complete. Read the CI/CD guide for GitHub Actions, Jenkins, and GitLab CI pipelines, including SARIF report retention and scan inputs.

WordPress administration

The WordPress 5.3+ plugin adds background scans, upload protection with a per-upload bypass filter for trusted integrations, passive traffic detection, optional AI finding review, categorized HTML, CSV, JSON, text, and SARIF report exports, quarantine, whitelist management, and controlled remediation to the dashboard. Scan activity charts retain every detection and divide each bar by status: unresolved, whitelisted, or remediated by quarantine, deletion, or cleaning; the next scheduled scan appears as a dotted marker. Its sensitivity control progresses from Signatures (the lowest alert volume) through Functions, Lite, and Exploits to Full (the broadest coverage). New installations use Lite scan mode by default, and report findings can show the detected code with surrounding lines and a highlighted match.

WordPress Antimalware Scanner dashboard

Two mutually exclusive packages are available:

Edition Distribution Browser file editing Restore quarantined files
AMWScan Antimalware Scanner Lite WordPress.org package WordPress plugin editor when permitted No
AMWScan Antimalware Scanner GitHub release Built-in editor Yes

When a detection’s source line is missing or outside the file, the WordPress details modal shows the file’s opening lines with a fallback notice instead of “Code context is unavailable.” Unknown locations display “Source line unknown,” not “Line 0.” You can retry failed code requests from the modal. The new fallback messages, unknown-location label, and retry action have translations in all nine bundled languages. File-hash verification and existing excerpt size limits still apply.

You can whitelist reviewed findings in files larger than the 2 MiB editor limit. Whitelisting leaves file contents unchanged and verifies the file hash before and after acquiring the report lock; it skips a redundant third hash check to reduce large-file overhead.

Both editions share settings and data. Remove the installed edition before switching. Dashboard progress polling uses a lightweight status request; report summaries refresh on scan-state changes and otherwise once a minute. WordPress scans expose pause, resume, cancel, phase, throughput, and ETA controls; dangerous-domain analysis defaults to script and web files and can be expanded or disabled. Report-detail tables fit their bento cells, open panels fill the height of each desktop grid row, and individual panels can expand to full width for review. Read the WordPress plugin guide for setup, schedules, upload scanning, and remediation.

Useful commands

# Exclude generated directories
php scanner /path/to/project --lite --report-only \
  --ignore-paths="*/cache/*,*/logs/*"

# Scan ZIP entries
php scanner /path/to/project --lite --report-only --scan-archives

# Save JSON progress and resume it
php scanner /path/to/project --report-format=json \
  --checkpoint=/private/amwscan-checkpoint.json --resume

# Scan a local WordPress database (interactive terminals offer confirmed cleanup)
php scanner /path/to/wordpress --scan-wordpress-db --report-format=json

# Ask Gemini for advisory malware or false-positive verdicts
GEMINI_API_KEY=your-key php scanner /path/to/project --report-only \
  --ai-provider=gemini --report-format=json

Browse the CLI reference for every option, default, conflict, and safety note.

Contributing

Bug reports, documentation fixes, tests, and reviewed detection improvements are welcome. Do not attach executable malware to a public issue. Submit detection metadata first so maintainers can arrange a private transfer when a sample is needed.

git clone https://github.com/marcocesarato/PHP-Antimalware-Scanner.git
cd PHP-Antimalware-Scanner
composer install
composer test

Read TESTING.md and the contribution guide before opening a pull request.

License

PHP Antimalware Scanner is available under the GNU General Public License 3.0 or later.