Add wp-abuse-and-compromise-response skill (response counterpart to planned wp-security)#62
Open
Vytas-cs wants to merge 4 commits into
Open
Conversation
…tion, cleanup, and post-cleanup hardening of compromised WordPress sites (WordPress#61) Adds a response-time skill complementary to the planned wp-security skill. Covers: triage with immediate salts rotation, signal-to-category classification across 9 compromise types, full investigation playbook (file/DB/log), two cleanup paths (backup-restore + manual), full credential rotation, verification, and post-cleanup hardening aligned with the WordPress.org hardening guide. Includes a deterministic fast-scan script that surfaces high-signal compromise indicators (PHP in uploads, eval+base64 patterns, mu-plugins presence, recent core mtimes, WP-flavored bait directories, drop-in audit). Three eval scenarios cover the main entry points: confirmed compromise, suspected-but-unconfirmed (cloaking pattern), and reinfection-after-cleanup (persistence mechanism focus). Audited against WordPress.org canonical sources before submission: - hacked-site FAQ: https://wordpress.org/documentation/article/faq-my-site-was-hacked/ - hardening guide: https://developer.wordpress.org/advanced-administration/security/hardening/ Registry updates: README skill table, docs/ai-authorship.md disclosure row, wordpress-router decision-tree routing entry for compromise/hacked/defaced/ malware/redirect/SEO-spam/phishing/mailer/cryptominer/reinfection intent. Refs WordPress#61
Contributor
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @Vytas-cs. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
…--check-vulns Adds an optional --check-vulns flag to detect_compromise_signals.mjs that: - Reads installed WP core version from wp-includes/version.php - Parses plugin headers from wp-content/plugins/<slug>/*.php - Parses theme headers from wp-content/themes/<slug>/style.css - Queries wpvulnerability.com (free, no API key, aggregates WPScan + Patchstack + WP.org sources) for each detected component - Filters returned vulnerabilities to those affecting the installed version - Adds a "known_vulnerabilities" signal block to the JSON report Why: a breach is often the result of an unpatched CVE in a specific plugin/theme/core version. Knowing which CVE points at the entry point and confirms the attack vector, which prioritizes patching during cleanup. SKILL.md §3 (investigate) now references --check-vulns and lists alternative data sources (Patchstack, WPScan, Wordfence Intelligence) for users who prefer direct queries. hardening.md §6 expanded into a fuller ongoing-scanning section with feed-source comparison and automated scan guidance. Refs WordPress#61
…ress#62 Blocking fixes: - Step 5 password reset: scope to admins/editors and --skip-email, so the reset no longer blasts a password-change email to every customer account on a WooCommerce/membership site (which would also tip off any attacker-controlled account). - detect_compromise_signals.mjs: downgrade recent_core_modifications from "high" to "review" — recent mtime in core dirs is just as easily a legitimate WP update as it is tampering. Wording now points to verify-checksums as the actual signal. - detect_compromise_signals.mjs: surface truncated / depth_capped / files_read_truncated flags from findFilesRecursive + scanMalwarePatterns. Summary now refuses to declare "clean" when the scan truncated, and recommends running verify-checksums + external scanner instead. - hardening.md: fix wp-config.php permission notation (440 is -r--r-----, not -rw-------) and modernize Apache snippets to Require all denied / FilesMatch syntax (the older Order Deny,Allow is mod_access_compat, deprecated since Apache 2.4). - detect_compromise_signals.mjs --check-vulns: mark experimental, add privacy note about exfiltrating installed component inventory to the third-party API, and fix vulnAffectsInstalledVersion returning true on unknown version (now returns null/uncertain, surfaced separately under vulnerabilities_uncertain_match so a missing version header doesn't flag every historical CVE). Correctness: - SKILL.md step 1: softened "salts rotation doesn't tip off the attacker" — it kills sessions, which is an observable signal, and doesn't defend against backdoors at all. Reworded to acknowledge. - hardening.md DB privilege restriction: added an explicit caveat that many plugins call dbDelta() at runtime (not just at activation), so a long-term SELECT/INSERT/UPDATE/DELETE-only runtime user will silently break things. Recommends most sites stick with the standard model. - hardening.md disable_functions: removed curl_multi_exec and parse_ini_file from the suggested list (both have legitimate plugin uses) and added explicit caveats for exec/shell_exec. Refs WordPress#61
… change)
Internal cleanup, output shape unchanged for the existing signal fields.
- findFilesRecursive: return { files, truncated, depthCapped } instead of
mutating the result array. Use a labeled break to drop a fully redundant
post-loop truncation check (line was dead — truncated is always set inline
at the cap, never reached otherwise).
- scanPhpInUploads + scanKnownMalwareFilenames: now propagate truncation
through to the output (previously dropped silently — same class of bug
reviewer caught for scanMalwarePatterns, fixed in all three places).
- summarize(): treats truncation in any walk-based scan as scan_truncated.
- parseWpPluginHeader + parseWpThemeHeader: unified into parseWpHeader(file,
kind, maxBytes). Header regex normalized to [\s/*]* (more permissive,
matches both PHP-comment and CSS-comment prefixes).
- detectInstalledPlugins: drop the manual candidate-dedup loop, just sort
.php files at the plugin-dir root with <slug>.php first.
- OPERATOR_PREDICATES map collapses the operator if-ladder in
vulnAffectsInstalledVersion.
- listDirSafe helper: collapses 4 try/readdirSync/catch sites.
- lookupComponentVulns helper: collapses the duplicated plugin/theme lookup
blocks in checkVulnerabilities; plugin/theme/core lookups now Promise.all
instead of sequential awaits.
- buildSignals + summarize: pulled out of main() for testability and to keep
main() at orchestration level (~15 lines).
- TOOL_HEADER constant: dedupes the {name, version} object literal across
the no-WP-found branch and the main branch.
- compareVersions comment: corrected to be honest about pre-release suffix
handling (treats "1.2.3-beta" as equal to "1.2.3"; fine for vuln-record
numeric thresholds).
- flattenVulnRecords: always returns error: null when present, consistent
shape; skip records confirmed-not-affected (affected === false) instead
of including them.
Net change: 622 -> 539 lines. Smoke-tested against fake WP install with
known plugin and confirmed --check-vulns round-trips through wpvulnerability.com
correctly (Akismet 5.3 -> 0 vulns, core 6.4.2 -> 0 vulns). Eval harness
still passes.
Refs WordPress#61
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #61
Summary
Adds a new skill
wp-abuse-and-compromise-responsecovering response to a suspected or confirmed WordPress site compromise: defacement, redirect injection, SEO spam, phishing-page host, mailer abuse, cryptominer, and supply-chain plugin attack.The skill walks AI assistants through:
This is response-focused. Upfront prevention (nonces, capability checks, sanitization/escaping) is the planned
wp-securityskill's territory — the two are complementary, not overlapping.What's included
skills/wp-abuse-and-compromise-response/SKILL.md— procedural overview (167 lines, in range with wp-performance and wp-plugin-development)skills/wp-abuse-and-compromise-response/references/:signals.md— full signal-to-category taxonomy across 9 compromise categoriesinvestigation.md— DB queries, log triage, file-system patternscommon-injection-points.md— catalog of where attackers hide (mu-plugins, autoload options, drop-ins, etc.)hardening.md— post-cleanup hardening checklistskills/wp-abuse-and-compromise-response/scripts/detect_compromise_signals.mjs— deterministic fast-scan helper, JSON output, matchesdetect_*.mjsconventioneval/scenarios/abuse-confirmed-redirect-cleanup.json— happy patheval/scenarios/abuse-suspected-but-unconfirmed.json— cloaking/SEO-spam triageeval/scenarios/abuse-reinfection-after-cleanup.json— focuses AI on persistence mechanismsRegistry updates
README.md— added skill to the available-skills tabledocs/ai-authorship.md— added authorship disclosure rowskills/wordpress-router/references/decision-tree.md— added compromise/hacked/defaced/malware/redirect/SEO-spam/phishing/mailer/cryptominer/reinfection intent → route to this skillAlignment with WordPress.org canonical guidance
The skill was audited against the hacked-site FAQ and the hardening guide before submission. Key alignments:
/wp-admin/in hardening.Validation
node eval/harness/run.mjs— passesnode skills/wp-abuse-and-compromise-response/scripts/detect_compromise_signals.mjs— returns valid JSON## When to use,## Inputs required,## Procedurewith### 0) Triagefirst,## Verification,## Failure modes / debugging,## Escalation)WordPress 6.9andPHP 7.2.24substringsAI authorship disclosure
Per the established
docs/ai-authorship.mdtable format:Opinionated calls (open to feedback)
mu-plugins/listed first in the persistence catalog — most commonly-missed hiding place across the WP community.wp-config.phpreconstructed from scratch, not cleaned — diffing isn't reliable enough; rebuild from known DB creds + fresh salts.Out of scope