Repository navigation
For Developers
| Name | Type | Use |
|---|---|---|
wp2ss_signatures |
Filter | Add or change indicators (fixed PHP versions, code patterns, hashes, IPs, log patterns…). Receives the array from includes/signatures.php. |
wp2ss_step_budget |
Filter | Seconds of work per slice (float). Lower it on very strict hosts. |
wp2ss_scan_complete |
Action | Fires with ( $report, $previous_report ) when a scan finishes |
wp2ss_fix_applied |
Action | Fires with the fix record after a one-click fix (quarantine or admin removal) |
wp2ss_fix_undone |
Action | Fires with the fix record after a restore or undo |
wp2ss_fleet_private_hub |
Filter | Return true to let this member report to a hub on a private network address |
WP2SS_FLEET_PRIVATE_HUB |
Constant | Same as the filter, from wp-config.php
|
WP2SS_DISABLE_UPDATER |
Constant |
define( 'WP2SS_DISABLE_UPDATER', true ); in wp-config.php stops all requests to GitHub |
Add your own indicators
add_filter( 'wp2ss_signatures', function ( $sig ) {
// [ severity, regex, description ]
$sig['code'][] = array( 'high', '/my_known_bad_function\s*\(/i', 'Our internal backdoor marker' );
$sig['sha1']['0123456789abcdef0123456789abcdef01234567'] = 'Sample from our incident';
// If PHP ships another fix, tell the scanner about it:
$sig['php_fixed']['8.4'] = '8.4.28';
// …or about a newly fixed distribution package: [ prefix, first fixed build ]
$sig['php_fixed_pkg'][] = array( '8.2.29-1~deb12u', 2 );
return $sig;
} );Post every result to Slack
add_action( 'wp2ss_scan_complete', function ( $report ) {
wp_remote_post( 'https://hooks.slack.com/services/XXX', array(
'body' => wp_json_encode( array( 'text' => "{$report['site']}: {$report['verdict']} (PHP {$report['php']['version']})" ) ),
'headers' => array( 'Content-Type' => 'application/json' ),
) );
} );What Download report (JSON) and wp jat-shell scan --format=json produce:
| Field | Type | Meaning |
|---|---|---|
id |
string | Unique ID of this scan |
site |
string | Site URL |
wp |
string | WordPress version |
php |
object |
version, sapi (server type), source (web, web-snapshot or cli) |
plugin |
string | Scanner version |
source |
string |
manual, cron or cli
|
args |
object |
core, log, error_log — what this scan was asked to do |
scanned |
string | Finish time, ISO 8601 UTC |
duration |
int | Seconds from start to finish |
verdict |
string |
CLEAN, REVIEW, VULNERABLE, SUSPICIOUS, COMPROMISED
|
stats |
object |
files, php_files, dirs, unreadable, links, large, errors
|
findings[] |
array | See below |
ignored |
array | IDs you ignored (dashboard download only) |
findings[] field |
Meaning |
|---|---|
id |
Stable 12-character ID (use with wp jat-shell ignore) |
severity |
critical, high, medium, low, info
|
type |
php, version, plugin, mu-plugin, user, rest, file, code, hash, core, log, scan
|
message |
What was found |
advice |
What to do about it |
location |
File path, user:<ID>, role:<name>, rest:<namespace>, or empty |
sha1 |
Fingerprint of the file, where relevant (so an ignored file that changes is flagged again) |
# Integration tests — they plant FAKE malware files, so only use a throwaway site
tests/integration.sh /path/to/throwaway/wordpress
# False-positive check — signatures vs. legitimate code
php tests/false-positives.php /path/to/wordpress /path/to/some/plugins
# Mermaid diagrams in this README
npm i mermaid@11 jsdom && node tests/check-mermaid.mjs README.mdWhat CI checks on every push
| Job | What |
|---|---|
| PHP syntax | Every file on PHP 7.0 – 8.5 |
| Integration | Real WordPress + MySQL: latest WP on PHP 7.4 and 8.4; WP 7.0, 7.0.1 and 6.9.4 (vulnerable); WP 6.4 on PHP 7.0. ~90 checks: PHP2Shell version logic and log evidence, wp2shell indicators, false-positive bait (Wordfence, Performance Lab, cache plugins…), evasion (padded files, symlinks, images, odd file names, hiding in the scanner), resumable slices, locking, cancellation, crash isolation, signed ignore list, admin baseline, self-integrity, exit codes. Fails on any PHP notice. |
| False positives | Signatures vs. WordPress core, WooCommerce, Yoast SEO, Elementor, Jetpack, Contact Form 7, WP Super Cache — zero High/Critical allowed |
| Docs | Every Mermaid diagram in this README must parse |
How a release happens
flowchart LR
A["Bump version in<br/>jat-shell-scanner.php ×2<br/>+ readme.txt"] --> B["Add CHANGELOG.md entry"]
B --> C["Push to main"]
C --> D["CI: lint, integration,<br/>false positives, docs"]
D -- all green --> E["Release workflow:<br/>versions match? new version?"]
E -- yes --> F["Zip + manifest.json + checksum<br/>tag vX.Y.Z, GitHub release"]
F --> G["Every installed site<br/>sees the update within ~12h"]
F --> I["Deploy workflow:<br/>WordPress.org build → SVN trunk + tag"]
D -- any red --> H["Nothing is released"]
WordPress.org build. bash .github/scripts/build-wporg.sh writes build/jat-shell-scanner/ and a zip of it: the same files minus the GitHub updater and the Update URI header. CI runs the official Plugin Check on that build. Once the plugin is approved on WordPress.org and the SVN_USERNAME / SVN_PASSWORD repository secrets are set, each GitHub release is also committed to WordPress.org SVN (trunk and tag), with the banner, icon and screenshots from .wordpress-org/.
Manual WordPress.org workflows (Actions tab → Run workflow): Deploy to WordPress.org publishes the current version again, and Update WordPress.org readme publishes only readme.txt and the .wordpress-org/ images, without a new version.
Wiki. The wiki is built from this README by .github/scripts/build-wiki.py, which splits the numbered sections into pages. The Wiki workflow rebuilds it whenever README.md changes on main, so edit the README, not the wiki.
Workflow actions are pinned to exact commits. Detection rules live in includes/signatures.php — new indicators are very welcome: open an issue or pull request with a link to the source.
Found a security problem in this plugin? Please report it privately via Security → Report a vulnerability on this repository — see SECURITY.md. New indicators aren't secret; share them as a normal issue or pull request.
This wiki is built from the repository's README.md by .github/scripts/build-wiki.py. To change a page, edit README.md: edits made here are replaced the next time the wiki is rebuilt.
For site owners
- PHP2Shell and wp2shell
- Install, scan and update
- Understanding your results
- What it checks
- Settings and alerts
- If your site is compromised
- Troubleshooting, logs and hosting
- FAQ
For agencies and developers
- WP-CLI
- Scanning many sites
- How it works, privacy and limits
- Hooks, report format and development
- Sources and license
Links