Performance Audit
The site was migrated from WP Engine to SiteGround in approximately December 2025, but the migration was never properly finalized. The result is a WordPress installation carrying significant dead weight from its previous host that actively degrades performance on every single page load.
Key findings:
The site was migrated from WP Engine but 5 WP Engine must-use plugins were left behind. These load on every single page request (frontend and backend) and cannot be deactivated through the WordPress admin - they are must-use plugins that load automatically.
The following WP Engine components are still active:
Additionally, the advanced-cache.php drop-in is from WP Engine's cache system, not SiteGround's SuperCacher.
WordPress has two layers of caching. The first is page caching - saving a complete copy of each page so it can be served instantly to visitors without rebuilding it from scratch. The second is object caching - storing individual pieces of data (settings, menus, widget content, query results) in fast memory so WordPress doesn't have to ask the database for the same information over and over.
Page caching is partially working. I confirmed from external testing that SiteGround's nginx proxy is caching pages for anonymous visitors:
This means a regular visitor browsing the site will get a reasonably fast experience because they're receiving a pre-built copy of the page. I measured the difference:
Object caching is completely broken. It is configured to use WP Engine's Memcached Redux plugin, pointing to a memory socket that only exists on WP Engine's servers - not on SiteGround.
In plain terms: every time WordPress needs a piece of stored data, it tries to grab it from a fast-memory location that doesn't exist, silently fails, and then falls back to querying the database directly. This happens hundreds of times per page load, especially on a site like this one that relies heavily on plugins to build its pages and filter its content.
Who this affects most:
The page cache is masking this problem for casual visitors, but the backend is doing far more work than it should be on every request that isn't served from the proxy cache.
Every scheduled cron event on the site is overdue. The earliest overdue event dates back to 18 December 2025 - nearly 3 months of accumulated, unprocessed scheduled tasks.
I confirmed this externally. When I requested the cron handler directly, it took 7 seconds to respond - a normal response should be near-instant. The long response time indicates the system is attempting to chew through a massive backlog of overdue tasks every time it's triggered:
Root cause identified: The WP Engine mu-plugin (wpengine-common/plugin.php) hooks into every cron request using a filter called cron_request. This filter injects WP Engine's basic authentication headers into the internal HTTP request that WordPress uses to trigger scheduled tasks. On SiteGround, those credentials are meaningless - the cron request either fails or gets rejected because the server doesn't recognize the authentication. In plain terms: every time WordPress tries to run a background task, the old WP Engine code steps in and adds the wrong "password" to the request, causing it to fail silently.
This confirms WP-Cron is broken because of the WP Engine code identified in Finding 1. These two findings are directly linked.
I also attempted to trigger cron manually during the audit by requesting wp-cron.php directly. Even after that request (which took 7 seconds), every scheduled event remained stuck at "now" (overdue) - the system was unable to process a single task. The cron queue is not just behind, it is completely jammed.
Server-side inspection confirmed 28+ overdue scheduled events, the earliest dating back to the migration:
Consequences of broken cron:
A full copy of the website's backup files is sitting inside the publicly accessible part of the server. Think of it like leaving a copy of your office keys and filing cabinet in an unlocked car in the parking lot - it's not visible from the street, but anyone who walks up to the car can open the door.
I verified this during the audit. By visiting the URL below, I confirmed that the server responds with a valid page (HTTP 200), proving the file is reachable from the open internet:
More critically, I discovered that the backup is not just a collection of static files - it is a fully functional second copy of the WordPress installation. The backup's login page is live and accessible to anyone on the internet:
The backup uses a different database name than the live site, but the same database user and password. This means the backup's database credentials have access to both databases. A compromised backup login could be leveraged to reach the live site's data through the shared database user.
Why this is a critical security issue:
backup, backup_2025, etc.I scanned the backup's plugin list against the WPScan vulnerability database. Multiple plugins in the backup have known, unpatched vulnerabilities:
| Plugin (in backup) | Backup Version | Vulnerability | Severity |
|---|---|---|---|
| Yoast SEO | 25.8 | Contributor+ Stored XSS (fixed in 26.9) | 5.9 Medium |
| WP Security Audit Log | 5.5.4 | Authenticated Stored XSS (fixed in 5.6.0) | 6.4 Medium |
| Simple History | 5.20.0 | Admin+ Info Exposure (fixed in 5.8.2) | 4.9 Medium |
| Code Snippets | 3.9.2 | CSRF to cloud snippet actions (fixed in 3.9.5) | 4.3 Medium |
The backup copy is also running 19 plugins with pending updates that will never install, since the backup has no working cron and is not maintained. Every future vulnerability disclosure for any of these 46 plugins adds another exploitable entry point through this backup.
In total, 6.46 GB of backup and migration debris is spread across the server:
The mysql.sql file is a complete database dump - it contains every user account, email address, form submission, and site setting. It is currently blocked by nginx (HTTP 403), but like the wp-config.php issue, any change to server configuration could expose it. A 13 MB database dump has no reason to exist in the web root.
The PHP error log is 932 KB and growing. Two recurring issues were identified:
A) Undefined variable in theme (every page view):
B) Fatal error in JetSmartFilters (AJAX filtering):
C) Elementor Pro featured image warning:
The site is running 24 active plugins plus 7 must-use plugins (5 of which are WP Engine remnants). Several plugins should not be permanently active:
| Plugin | Status | Issue |
|---|---|---|
| WP File Manager | Remove Immediately | This plugin provides a web-based file browser with full server access. It was the target of a mass exploitation campaign in 2020 (CVE-2020-25213, CVSS 10.0 - unauthenticated remote code execution) that compromised hundreds of thousands of WordPress sites. Verified: plugin is installed and reachable at /wp-content/plugins/wp-file-manager/ (HTTP 200). The 2020 exploit endpoint is currently blocked (HTTP 403), but the plugin's purpose - giving browser-based access to all files on the server - makes it a high-value target for attackers. |
| WPE Site Migration | Deactivate | Migration is complete. No reason to keep active. |
| Better Search Replace | Deactivate | Database tool - activate only when performing search/replace operations. |
| WordPress Importer | Deactivate | One-time import tool. No need to keep active. |
| Duplicate Page | Review | Lightweight but assess if still needed. |
| UpdraftPlus | Review | Redundant if SiteGround's daily backups are enabled. |
| Wordfence | Keep | WAF is actively protecting the site (verified: blocking xmlrpc and author enumeration). Stale .htaccess rules are dead weight but not harmful. |
| HubSpot (leadin) | Review | Makes external API calls. Confirm if CRM integration is actively used. |
| WP Sheet Editor (4 plugins) | Review | Admin-only bulk editing suite. Confirmed not loading on the frontend. |
Wordfence's Web Application Firewall is configured via .htaccess using auto_prepend_file directives targeting mod_php5, mod_php7, and mod_php. SiteGround uses PHP-FPM, not mod_php.
These .htaccess rules are dead weight from the old hosting environment and are parsed on every request without doing anything. The good news is that Wordfence is actively protecting the site through its .user.ini fallback method, which is the correct approach for PHP-FPM. I verified this externally:
Every form on the site is configured to send email notifications from email@sensiblesite.wpenginepowered.com - the old WP Engine staging domain. This domain is no longer under Sensible's control. Emails sent from a domain you don't own are likely being rejected by mail servers or landing in spam folders, which means customer inquiries submitted through the website may never be received.
This affects every page that contains a form, including the most important lead generation pages on the site. The forms themselves still appear and can be submitted, but the email notifications generated from those submissions are sent using an address on a domain Sensible no longer controls. Most email providers will reject or spam-filter these messages.
I also found that form notification copies are still being sent to ethan@yakk.com.au.
Every user account on the site has full administrator access. There are no editor, author, or subscriber-level accounts. While the active accounts all appear to be legitimate, the number of full administrators and the presence of an unused generic account are worth reviewing.
| User | Role | Last Login | Status |
|---|---|---|---|
| raysweeney | Administrator | 12 March 2026 | Client - Active |
| yakkbasetheme (ethan@yakk) | Administrator | 9 March 2026 | Yakk (SEO/Dev) - Active |
| luke@yakk.com.au | Administrator | 4 February 2026 | Yakk - Confirm still needed |
| webadmin | Administrator | Never | Generic shared account - never used |
The webadmin account uses a generic Microsoft 365 email address (webadmin.bg@SensibleBiz.onmicrosoft.com) and has never been used to log in. Generic shared accounts are a security risk because there is no accountability for actions taken under that login - if it were compromised, there would be no way to determine who was responsible. If this is intended as a "break glass" emergency account, it is unnecessary - a new administrator account can always be created via SSH using WP-CLI or directly in the database if needed.
It's also worth confirming whether both Yakk accounts need full administrator access, or whether one of them could be downgraded to an Editor role. The fewer administrator accounts on a site, the smaller the attack surface.
Several security hardening measures that are considered standard practice are not in place:
DISALLOW_FILE_EDIT constant is not set, which means any administrator can edit PHP theme and plugin files directly from the WordPress dashboard. If an admin account is compromised, an attacker can inject malicious code without needing server access.