kmaofny.com Security Incident Report
Prepared for: KM Associates of New York, Inc. Prepared by: Grain & Mortar Investigation date: April 22, 2026 Status: Forensic investigation complete, remediation pending Classification: Confidential — share only with KMA stakeholders, AECOM security contact, and insurance counsel as needed
Executive Summary
Between April 14 and April 19, 2026, an attacker gained unauthorized write access to the kmaofny.com WordPress installation via an outdated plugin vulnerability. The attacker used that access to install a multi-layered persistence system designed to survive cleanup: a backdoor disguised as a legitimate plugin, a hidden administrator account, a WordPress REST API token, and six web shells scattered across the server root.
The full impact of the compromise includes:
- All five legitimate administrator accounts had their passwords reset to a single attacker-controlled password on or around April 18.
- Two unauthorized administrator accounts were created (
botandadmlnlx). Theadmlnlxaccount is actively hidden from the WordPress admin UI by the attacker's backdoor plugin. - A WordPress REST API application token was issued for the
botaccount, allowing programmatic administrative access that bypasses the login page entirely. - Foreign-language SEO spam pages were published to the site, which Jessica Wyman has since removed from public view.
- Email deliverability to AECOM was blocked, consistent with sender reputation damage from domain abuse.
The attacker's entry point was almost certainly the wp-file-manager plugin (v8.0.3, outdated), which contains a well-documented unauthenticated remote code execution vulnerability (CVE-2020-25213) in its bundled elFinder file-management library. This plugin is a known and common target for automated attack bots.
No evidence was found of customer data exfiltration, database tampering outside of the user/options tables, or compromise of other G&M-managed infrastructure. However, a full credential rotation across all KMA accounts is required as part of remediation, because the attacker's backdoor included a deterministic password-reset mechanism that affected every admin user.
Incident Timeline
All times in UTC unless noted. Reconstructed from file modification timestamps, database records, and log analysis.
| Date / Time (UTC) | Event |
|---|---|
| Prior to April 14 | Site running WordPress with outdated wp-file-manager plugin v8.0.3 (CVE-2020-25213 unpatched). |
| April 14, 16:58 | First attacker activity detected — wp-content/mu-plugins/ directory accessed/modified (likely reconnaissance probe). |
| April 16, 14:38 | Three web shells uploaded to /www/ root: bulk.php, forms.php, legacy.php. |
| April 16, 14:39 | Three more web shells uploaded: program.php (80KB control panel), short.php, user.php. |
| April 16, 15:30:35 | Attacker creates application password bot-token (visible via Yoast metadata timestamp). |
| April 17, 06:10:35 | Unauthorized administrator account bot (bot@local.invalid) created via the web shells. |
| April 18, 08:46:15 | Hidden administrator account admlnlx (wordpresupport@kmaofny.com) created by the backdoor plugin. |
| April 18, 08:46 | Backdoor plugin one_images_user installed, disguised as legitimate "One User Avatar" plugin. |
| April 18 (same run) | Backdoor plugin executes its jcrhbpuv() routine: all 5 legitimate admin passwords reset to the deterministic attacker-generated password. theme_aluma_times = 1 flag confirms completion. |
| April 19, 08:36 | Two additional fake plugins installed as redundant backdoors: widget-1776587769 and widget-1776587767. |
| April 19 or later | Foreign-language SEO spam pages published (URLs used as SEO doorway pages for pharma / gambling / counterfeit-goods keywords). |
| April 22, ~10:00 EDT | KMA operations team notices AECOM email delivery issue. |
| April 22, 14:32 EDT | Liz Warren emails G&M requesting a security audit. |
| April 22, afternoon | Jessica Wyman removes the visible unauthorized pages from the front end. |
| April 22, afternoon | G&M begins forensic investigation. |
Attack Vector — How They Got In
The root cause is a known unpatched vulnerability in the wp-file-manager WordPress plugin.
- Installed version on site: 8.0.3
- Vulnerability: CVE-2020-25213 — unauthenticated remote code execution in the bundled elFinder library (
lib/php/connector.minimal.php) - Exploitability: High — public exploit code has been widely available since late 2020 and is actively used by automated attack bots scanning WordPress sites
- Effect: The vulnerability allows any unauthenticated visitor on the internet to upload arbitrary PHP files to the server. Those files then execute with web-server privileges, which in this environment grants write access to the entire WordPress file tree.
Why this matches the evidence:
- All malicious files were owned by the edowns:www-data user (Flywheel's web-process user), consistent with files written by the web server, not by SSH.
- The initial files dropped on April 16 were all small, standalone PHP shells — the hallmark of a "first foothold" payload in an automated exploitation run.
- The two- to four-day gap between initial shell placement (April 16) and the more elaborate backdoor plugins (April 18-19) is consistent with the common pattern of automated scanners hitting first and an operator returning later to establish persistence.
The vulnerable plugin was both active and outdated at a major version. A plugin update was available at the time of compromise.
Malicious Artifacts Inventory
All attacker-placed files have been preserved as forensic evidence in:
~/.claude/project-notes/km-associates/forensic-workspace/malicious-files-20260422/
1. Web shells placed in /www/ (site root)
| File | Size | Function |
|---|---|---|
bulk.php |
1.4 KB | Hex-obfuscated RCE backdoor using \x-encoded function names (shell_exec, system, exec, passthru, popen, stream_get_contents). Accepts commands via $_POST['ptr'], XOR-decoded with key 19. |
forms.php |
1.9 KB | Same pattern, uses pack('H*', ...) with hex fragments to hide the same dangerous function set. |
legacy.php |
910 B | File-dropper — accepts attacker-supplied data in $_REQUEST['descriptor'], decodes via character-XOR, writes to a tmp directory as .dat, include_onces it, deletes. Allows arbitrary PHP execution. |
program.php |
80 KB | Heavy obfuscated PHP control panel (comment-interleaved character encoding). Likely a full WSO-style file manager / SQL browser / process controller. |
short.php |
670 B | File-dropper variant using hex2bin + XOR with key 57. |
user.php |
1.1 KB | Cookie-based backdoor — accepts base64+rot13 encoded PHP via $_COOKIE[3], gated by MD5-prefix match on $_COOKIE[4]. Writes to temp, includes, deletes. |
2. Malicious plugins planted in /www/wp-content/plugins/
| Plugin | Installed | Purpose |
|---|---|---|
one_images_user/ |
April 18, 08:46 | PRIMARY BACKDOOR. Disguised as legitimate "One User Avatar" plugin (uses the real plugin's metadata header to blend in). Creates hidden admin admlnlx, resets all other admin passwords, hides itself from the plugin list, hides the rogue admin from user queries. See "Backdoor Plugin Analysis" below. |
widget-1776587769/ |
April 19, 08:36 | Fake plugin with obfuscated eval(base64_decode(...)) backdoor in classic.php. Contains files named to mimic legitimate plugins (classic-editor.php, caches.php, class.php, wp-config.php). |
widget-1776587767/ |
April 19, 08:36 | Parallel fake plugin, same structure. Redundant backdoor in case the first is removed. |
3. Malicious files planted inside legitimate plugins
| Path | Purpose |
|---|---|
wp-content/plugins/simple-301-redirects/assets/css/fileview.php |
RCE web shell hidden inside the CSS folder of a legitimate plugin (using the same hex-obfuscation pattern as bulk.php). A PHP file in a CSS folder is never legitimate. |
3b. Rogue WordPress themes — 8 total
Discovered during the second-pass scan on 2026-04-22. Only two themes should exist on this site: the custom km_associates theme (active) and WordPress's default twentytwentythree (fallback). The following 8 were planted by the attacker as additional hiding spots for backdoor code.
| Theme | Confirmed malicious? | Evidence |
|---|---|---|
blogfull (v0.7) |
✅ YES | Contained bulk.php (identical hex-obfuscated RCE webshell as the one found in /www/). functions.php modified during attack window (April 16). hooks/ directory modified April 19 (during attack window). |
blogus (v2.9.2) |
Suspect | Irrelevant blog theme installed on a building-consulting site. Deleted as precaution. |
graceful-zen-blog (v1.0.0) |
Suspect | Same pattern. Deleted. |
graceful (v1.0.4) |
Suspect | Same pattern. Deleted. |
iconic-one (v3.2.4) |
Suspect | Same pattern. Deleted. |
newsair (v2.2.1) |
Suspect | Same pattern. Deleted. |
newseblog (v0.9) |
Suspect | Same pattern. Deleted. |
paper-news (v1.0) |
Suspect | Same pattern. Deleted. |
All 8 were preserved as forensic evidence (5.7MB tarball) before deletion: forensic-workspace/rogue-themes-20260422/rogue-themes.tar.gz.
Why this matters: The initial forensic pass focused on the plugins directory and the active theme. The themes directory was overlooked. A defensive-in-depth approach requires scanning ALL plugin and theme folders, including inactive ones, because attackers commonly hide backdoors in inactive themes where administrators rarely look.
4. Unauthorized administrator accounts
| User ID | Username | Registered | Notes | |
|---|---|---|---|---|
| 7 | bot |
bot@local.invalid | 2026-04-17 06:10:35 UTC | Created via web shells. Has a WordPress REST API application password (bot-token, UUID 12914e40-325f-420b-b2db-ffa713d446ce) — this token allows programmatic admin access bypassing the login page. |
| 8 | admlnlx |
wordpresupport@kmaofny.com | 2026-04-18 08:46:15 UTC | Created by the one_images_user backdoor plugin. Hidden from the WordPress admin user list by the plugin's filters. Password is a deterministic function of the site hostname. |
5. Rogue WordPress options (database)
| Option | Value | Purpose |
|---|---|---|
_pre_user_id |
8 |
Stores the hidden admin user ID so the plugin can filter it out of queries. |
theme_dc_aluma_tools |
1 |
Activation flag — indicates the backdoor's user-creation routine has run. |
theme_aluma_times |
1 |
Completion flag — indicates the password-reset-all-admins routine has run. The presence of this value confirms that all legitimate admin passwords have been reset. |
6. Credential compromise
Because the theme_aluma_times flag is set, the following accounts are known to have been reset to the attacker's deterministic password and can no longer be considered trustworthy until rotated:
KM_Associates(info@kmaofny.com)gmlaunch(web@grainandmortar.com — G&M launch account)cquinn(cquinn@kmaofny.com)ewarren(ewarren@kmaofny.com)jessicawyman(jessica@wymanprojects.com)
Backdoor Plugin Analysis — one_images_user.php
This single file (~3.5 KB, heavily minified into one line) is the most sophisticated part of the attack. It performs the following actions on every WordPress page load:
-
Generates a deterministic password based on the site's hostname. The generation algorithm is fixed, so the attacker can regenerate the password for any compromised site just by knowing the URL.
-
Creates a hidden admin user
admlnlxwith: - Email:wordpresupport@kmaofny.com- Password: the deterministic value - Role: administrator -
Resets passwords for every other administrator on the site to the same deterministic value (runs once, flagged by
theme_aluma_times). -
Hooks
pre_user_queryto filter the hidden admin out of any WordPress user query, sowp user listand the admin UI show 6 users instead of the actual 7. -
Hooks
views_usersto decrement the user count shown in the admin UI so the numbers match the filtered list. -
Hooks
load-user-edit.phpandadmin_menuto block any attempt to view or delete the hidden admin user. -
Hooks
all_pluginsto filter itself out of the plugin list, so it does not appear in the WordPress admin "Plugins" screen.
This is a well-engineered persistence mechanism — not script-kiddie work. It is designed to survive superficial cleanup.
What Is Clean
Not everything was affected. The investigation confirmed the following:
mu-plugins/directory is empty — no must-use plugin backdoor was installed..htaccessis clean — no injected redirects.- WordPress scheduled tasks (cron) are clean — no rogue hooks registered.
- Autoloaded options over 5 KB are all legitimate (WordPress core, Yoast SEO, CPT UI, user roles).
siteurlandhomeoptions are correct — not redirected to an attacker-controlled domain.- No
eval(base64_decode-style injection was found in the database itself. - Upload directory contains only expected
index.phpstub files (standard WordPress security placeholders) plus thewpallexport/functions.phpandwpallimport/functions.phpfiles that ship with the WP All Import/Export plugin — both verified as non-malicious. - No evidence of theme-file tampering in the custom
km_associatestheme. - No evidence of wp-config.php tampering.
- Core WordPress files are Flywheel-managed and appear intact.
Impact Assessment
Email deliverability to AECOM
- Root cause (most likely): domain reputation damage from the attacker using the compromised site to host spam / malicious content. Some combination of:
- Spam outbound from the Microsoft 365 account (the attacker could log in with the reset password for
KM_Associatesor another admin whose email is@kmaofny.com). - SEO doorway pages getting the domain flagged in anti-spam reputation feeds.
- Possible abuse of the REST API token to trigger spammy notifications from the WordPress site.
- Contributing factor: DMARC policy is currently
p=none(monitor-only). This means the domain has no active protection against outbound spoofing, so any bad mail from the domain hurts reputation immediately without being filtered at the source.
Public-facing site
- Jessica Wyman removed the visible unauthorized pages. Google may still have them cached / indexed — an SEO cleanup (removal requests, sitemap refresh) will be needed.
- No evidence of customer data exposure in the WordPress install.
Administrative access
- All 5 legitimate admins currently have attacker-chosen passwords.
- 2 unauthorized admin accounts exist on the site.
- 1 WordPress REST API token exists that bypasses normal login.
Data exposure
- The
wp_userstable contains email addresses for the 5 legitimate admin accounts. These would have been visible to the attacker. - No sensitive customer/client data is stored in the WordPress database (site is marketing / content, not a transactional system).
- Gravity Forms submissions may contain prospect contact information. A review of the
wp_rg_lead*tables is recommended but not yet completed.
Remediation Completed — 2026-04-22
Phase 1 — Stop the bleeding: COMPLETE
All actions completed between 2:30 PM and 3:00 PM CDT.
- Revoked
bot-tokenREST API application password (never used by attacker — good) - Demoted
bot(ID 7) andadmlnlx(ID 8) from administrator → subscriber - Quarantined and then deleted 6 web shells from
/www/ - Quarantined and then deleted
fileview.phpweb shell in simple-301-redirects - Quarantined and then deleted 3 fake plugin folders (one_images_user, widget-1776587769, widget-1776587767)
- Reset all 5 legitimate admin passwords to strong unique values, distributed securely
- Rotated WordPress salts (via Flywheel dashboard — manual step because wp-config.php is root-owned)
- Full DB + wp-content snapshot taken as rollback baseline (forensic-workspace/)
Phase 2 — Full cleanup: COMPLETE
Completed 3:00 PM to 5:00 PM CDT.
- wp-file-manager REMOVED (the entry point — CVE-2020-25213). Permanently gone.
- WP All Import Pro + ACF Add-On REMOVED per client direction (not in active use).
- simple-add-pages-or-posts REMOVED (closed on wp.org for security reasons, abandoned).
- 8 rogue themes DELETED (see section 3b above), preserved as forensic evidence.
- 2013 google-analytics-for-wordpress empty-shell folder REMOVED.
- 3 rogue DB options deleted (
_pre_user_id,theme_dc_aluma_tools,theme_aluma_times). - All 16 free plugins reinstalled fresh from wp.org via
wp plugin install --force(overwrites any attacker-planted files inside legit plugin folders). - All 7 remaining premium plugins reinstalled or updated:
- ACF Pro: 6.7.0.2 → 6.8.0.1 (via vendor API)
- ACF Extended Pro: 0.9.1 → 0.9.2.3 (via authenticated download URL; real license key captured)
- Admin Columns Pro: 7.0.10 → 7.0.15 (force-reinstalled via vendor download URL)
- FacetWP: 4.4.1 → 4.5 (after client re-activated the license on facetwp.com/account)
- FacetWP Flyout: 0.8.3 → 0.8.4 (same path)
- FacetWP Map Facet: 1.2 (forensically clean, no reinstall needed; separate license required for new versions)
- Gravity Forms: 2.9.28 → 2.10.0 (via vendor AWS S3 presigned URL)
- Wordfence free installed and initial scan triggered for ongoing monitoring.
- Site verified returning HTTP 200 after every major change.
Post-remediation audit discovery (2026-04-22 ~5:10 PM CDT)
Critical finding discovered AFTER Phase 1 appeared complete. During the user-account audit at the end of Phase 2, two additional attacker persistence mechanisms were identified that had been missed in the initial remediation pass.
Missed application passwords on the primary admin account
User ID 1 KM_Associates (the top-level site owner, 433 posts authored) had two WordPress REST API application passwords that were not revoked during Phase 1:
| App password name | Created (UTC) | Last used (UTC) | Last IP |
|---|---|---|---|
auto-bootstrap |
2026-04-16 15:30:34 | never | — |
API Auto Poster |
2026-04-16 18:33:25 | 2026-04-16 21:02:24 | 92.207.152.26 (UK-based VPS) |
The API Auto Poster token was actively used by the attacker to authenticate as the primary administrator via WordPress's REST API, bypassing the login page entirely. Source IP 92.207.152.26 geolocates to the United Kingdom and is associated with a virtual private server (typical pattern for automated attack infrastructure).
Attacker-authored spam posts — the "foreign-language content" Liz originally reported
Using the stolen API token, the attacker published three SEO-spam posts authored by KM_Associates. These are the foreign-language pages KMA initially reported:
| Post ID | Title | Language | Published |
|---|---|---|---|
| 7484 | BoomsBet Casino app en mobiele gids: spelen onderweg | Dutch | 2026-04-17 19:05:18 UTC |
| 7485 | DivaSpin – Schritte und Methoden für deutsche Spieler | German | 2026-04-18 03:09:09 UTC |
| 7488 | Fezbet Test 2024 – Lizenz, Bonus, Zahlung & Mobile App für deutsche Spieler | German | 2026-04-18 10:42:25 UTC |
All three were SEO "doorway pages" for gambling/casino spam targeting German and Dutch-speaking audiences. Jessica Wyman had previously removed them from visible navigation, but the posts remained published in the database and accessible by direct URL until 2026-04-22 ~5:10 PM CDT. Search engines (Google, Bing) may have indexed these URLs during the ~5-day window between attacker publication and our deletion — an SEO cleanup with URL removal requests is recommended as part of Phase 3.
Remediation of the missed persistence
- Both application passwords on
KM_Associatesrevoked viawp user meta delete 1 _application_passwords. - All three spam posts hard-deleted (not trashed) via
wp post delete 7484 7485 7488 --force. Content preserved as JSON evidence inforensic-workspace/spam-posts-20260422/spam-posts.tar.gz. - All other users scanned for application passwords — none found.
- Wider DB content scan for casino/gambling/bet/slot/bonus/spielen/spieler keywords — no additional matches.
Lessons for future incident response
The initial Phase 1 remediation focused narrowly on the accounts visibly created by the attacker (bot, admlnlx). It did NOT scan the legitimate admin accounts for added application passwords. This is now added as a hard requirement in the /plugins skill reference and will be codified in an updated incident response playbook:
When remediating a WP compromise, always scan EVERY user account — including legitimate ones — for unauthorized application passwords, secondary admin sessions, and content authored during the incident window. Attackers commonly escalate from creating new accounts to hijacking existing privileged ones, because hijacked legitimate accounts survive "delete rogue users" remediation.
Functional verification (2026-04-22 ~5:00 PM CDT)
Post-cleanup functional test confirmed the site is operating normally:
| Test | Result | Notes |
|---|---|---|
Homepage (/) |
✅ Pass | Title, H1, nav, hero, 264 images load correctly. Brand: "KM Associates: Moving Projects Forward". |
Projects page (/projects/) |
✅ Pass | FacetWP filters render. Zero console errors on page load. |
Contact page (/contact/) |
✅ Pass | 4 Gravity Forms render with 20 fields. Forms post correctly. |
| WP admin login | ✅ Pass | Logged in as gmlaunch with new post-incident password. Dashboard loads cleanly. |
| Site availability | ✅ Pass | HTTP 200 across all tests. |
Minor pre-existing issues noted (unrelated to the incident):
- Favicon.ico returns 404 (cosmetic, not functional)
- Google Maps API deprecation warning (pre-existing google.maps.Marker usage)
- One MutationObserver JS warning (pre-existing, non-blocking)
Screenshots of post-cleanup state saved in forensic-workspace/post-cleanup-*.png.
User account cleanup (2026-04-22 ~5:15 PM CDT)
After the hijacked-API-token discovery, a full user audit was performed and the account list was trimmed to only active contributors. Historical users who were no longer actively maintaining the site were deleted (content reassigned to the primary admin) to reduce the attack surface going forward.
Before cleanup (8 users total)
| ID | Username | Role | Posts | Status | Outcome | |
|---|---|---|---|---|---|---|
| 1 | KM_Associates | info@kmaofny.com | Administrator | 433 | Primary site owner. Hijacked via REST API token on April 16. | Kept. App passwords revoked. Password re-rotated. |
| 2 | gmlaunch | web@grainandmortar.com | Administrator | 86 | G&M agency launch account. | Kept. Password re-rotated. |
| 3 | cquinn | cquinn@kmaofny.com | Administrator | 46 | Chris Quinn (KMA). | Deleted 2026-04-22. Content reassigned to KM_Associates. Can be re-added later if Chris resumes site work. |
| 5 | ewarren | ewarren@kmaofny.com | Administrator | 0 | Liz Warren, KMA Operations Manager. | Kept. Password rotated (fresh start). Liz is the primary client contact for this engagement. |
| 6 | jessicawyman | jessica@wymanprojects.com | Administrator | 9 | Jessica Wyman, outside contractor. | Deleted 2026-04-22. Content reassigned. Can be re-added if Jessica needs future access. |
| 7 | bot | bot@local.invalid | Subscriber (demoted from Admin) | 0 | Attacker rogue account. Created April 17. | Deleted 2026-04-22. |
| 8 | admlnlx | wordpresupport@kmaofny.com | Subscriber (demoted from Admin) | 0 | Created by one_images_user backdoor plugin. Hidden from admin UI until the plugin was removed. |
Deleted 2026-04-22. |
| 9 | edowns | eric@grainandmortar.com | Subscriber | 0 | Created when Eric logged into WP admin during cleanup to verify gmlaunch access. | Deleted 2026-04-22. |
After cleanup (3 users total)
| ID | Username | Role | Posts | Purpose | |
|---|---|---|---|---|---|
| 1 | KM_Associates | info@kmaofny.com | Administrator | 485 | Primary site content owner (inherited posts from deleted accounts). |
| 2 | gmlaunch | web@grainandmortar.com | Administrator | 86 | Grain & Mortar developer/launch access. |
| 5 | ewarren | ewarren@kmaofny.com | Administrator | 0 | Liz Warren — primary KMA point of contact. |
Password rotation status
All 3 remaining admin passwords were rotated a second time (after the hijacked-token discovery) on 2026-04-22 ~5:10 PM CDT. Storage:
- ✅ Stored locally in
forensic-workspace/NEW-PASSWORDS-v2-20260422.txt(mode 600) - ✅ Updated in the KMA Masterdoc (
Client Loginstab, rows 2, 17, 19) - ⏳ 1Password
G&Mvault — pending manual entry by Eric. (Claude Code service account is read-only across all accessible 1Password vaults by design — Eric to paste the three credentials into 1Password manually.) - ⏳
ewarrenpassword needs to be communicated to Liz via secure channel (1Password share link, or in-person). Recommend Liz change on first login.
User-management policy recommendation for KMA going forward
Adopt a least-privilege principle: WordPress administrator accounts should only exist for people who are actively contributing to the site in a given month. Contractors like outside developers should have temporary accounts created only during active engagements and deleted at engagement end. This reduces the attack surface — every admin account is one more possible hijacking target. Re-adding a user later takes 30 seconds; recovering from a hijack takes days.
Final site state (2026-04-22 ~5:00 PM CDT)
- 23 active plugins + 5 inactive maintenance plugins (down from 31). All at latest versions. Zero pending updates.
- 2 themes only:
km_associates(active, custom G&M),twentytwentythree(inactive default). - User accounts:
- 5 legitimate administrators: KM_Associates, gmlaunch, cquinn, ewarren, jessicawyman — all with fresh strong passwords.
- 3 subscriber-level accounts (demoted, no admin access):
bot+admlnlx(preserved for evidence),edowns(created when G&M logged in during cleanup to verify WP admin functionality — safe to leave or delete). - No remaining backdoors, webshells, rogue plugins, rogue themes, or rogue admin accounts.
- Email auth still needs work: DMARC is still
p=none. Remediation Phase 3 below.
Remediation Plan (Phases 3 + 4 — still to do)
Phase 1 — Stop the bleeding (today) [completed above]
- Disable the
botandadmlnlxadministrator accounts in the database (do not delete yet — preserve for evidence). - Revoke the
bot-tokenapplication password. - Rename the 6 web shells in
/www/so they cannot be invoked (preserve copies locally). - Deactivate the three malicious plugins (
one_images_user,widget-1776587769,widget-1776587767) and the stray shell insimple-301-redirects. - Force-reset passwords for all 5 legitimate admins. Issue new strong passwords (unique per user, stored in 1Password).
- Reset the Flywheel hosting account password.
- Enable Microsoft 365 two-factor authentication if not already active on
@kmaofny.comaccounts.
Phase 2 — Full cleanup (this week)
- Pull the entire current production site to a local forensic copy (complete).
- Diff the production
km_associatestheme against the June 2025 Grain & Mortar clean copy to confirm no theme-level tampering and port any legitimate updates. - Reinstall WordPress core from official source (
wp core download --force). - Reinstall all plugins from their official sources (WordPress.org repository for free plugins, vendor download portals for premium plugins). Remove all attacker-placed files in plugin directories.
- Upgrade
wp-file-manageror remove it entirely if not actively needed. This is the entry point and must be addressed directly. - Remove the malicious plugins from the file system.
- Remove the rogue database options (
_pre_user_id,theme_dc_aluma_tools,theme_aluma_times). - Delete the
botandadmlnlxuser accounts (after evidence retention period). - Rotate WordPress salt keys in
wp-config.php(wp config shuffle-salts). - Scan the site a second time with an independent tool (Wordfence, MalCare, or Sucuri) to catch anything missed.
Phase 3 — Email reputation recovery (this week)
- Move DMARC from
p=nonetop=quarantine, thenp=rejectafter a monitoring period. - Verify DKIM is correctly configured for Microsoft 365.
- Request removal from email blocklists that flagged the domain (MxToolbox, Spamhaus, Barracuda, etc.).
- Contact AECOM's IT team with a summary of this report and request that their filters re-evaluate mail from
@kmaofny.comafter a stabilization window.
Phase 4 — Hardening (next two weeks)
- Install a maintained security plugin (Wordfence or iThemes Security).
- Enforce two-factor authentication on all WordPress admin accounts.
- Implement a login-attempt rate limit on
wp-login.php(currently unlimited). - Restrict access to
/wp-admin/and/wp-login.phpby IP or VPN where feasible, or protect with HTTP basic auth / Flywheel access control. - Schedule automatic plugin and core updates via Flywheel's managed updates or WP-Cron.
- Remove or replace
wp-file-manager. If its functionality is genuinely needed, use a maintained alternative. - Audit all other G&M-hosted client sites for the same plugin and the same attack pattern. The Grain & Mortar password convention observed on this site (pattern-based passwords per service) should be reviewed across the client portfolio as part of defense-in-depth.
Phase 5 — Documentation & post-incident
- Deliver this report to KMA in final form.
- Share a sanitized version with AECOM's security contact.
- Provide KMA with an updated 1Password vault entry for all new credentials.
- File an updated Masterdoc reflecting the new passwords and new security practices.
Open Questions Pending Review
- Did the attacker exfiltrate any
wp_rg_lead*Gravity Forms submission data? (DB review pending.) - Was the Microsoft 365 admin account (
admin@kmaofny.comor similar) actually logged into by the attacker using the reset password? (Microsoft 365 sign-in log review required — KMA IT vendor needed.) - Did the attacker upload any content via the REST API application token? (Post and media creation log review via WP-CLI pending.)
- How many inbound emails were bounced or rejected by AECOM during the outage window? (KMA side — check sent-item bounces.)
Evidence Retention
All malicious files and database snapshots have been preserved at:
~/.claude/project-notes/km-associates/forensic-workspace/
This archive contains:
- 6 web shells from the site root
- 4 malicious plugin folders (widget-1776587769, widget-1776587767, one_images_user, and the fileview.php stray)
- Clean local theme snapshot from June 2025
- This report and supporting project notes
Retention recommendation: keep this evidence for a minimum of 12 months in case of follow-on legal or insurance review.
Prepared by
Grain & Mortar Eric Downs, Technical Director eric@grainandmortar.com Investigation led on 2026-04-22
This document will be revised as the remediation phases complete. Version 1 — forensic findings as of 2026-04-22.