Audit #33 Benign
Show full summary
Verdict: BENIGN. Five plugins published by author Mathew (mathewt) on wp.org — add-as-preferred-source (90 installs), browser-address-bar-color-changer (50), image-zoom-on-hover (30), disable-right-click-content-copy-protection (20), announcement-notification-bar (10) — all received a synchronized release on 2026-05-05 (07:35-07:41 UTC) that adds an opt-in deactivation-feedback telemetry module. We checked the entire portfolio: there is no supply-chain attack shape, no code-execution vector, no authentication bypass, and no covert functionality. Sites running these plugins are not compromised.
What the new module does: When a site administrator deactivates the plugin from the Plugins screen, a feedback modal appears asking why. On submit, the plugin POSTs a JSON payload (site_name, site_url, wp_version, plugin_version, deactivation reason, plus an optional admin_email field the user can fill in) to https://startling-malasada-45aa0d.netlify.app/.netlify/functions/feedback with a server-side X-Relay-Secret: airtable-2026-mathew header. This is a standard opt-in feedback shape — the same pattern used by Freemius, Appsero, and most premium-plugin SDKs — but with a personal Netlify auto-named subdomain instead of a branded vendor host.
Why we audited: The module surfaced in our daily diff-review (/beacon-audit-diff) on 2026-05-05 because two of Mathew's plugins (add-as-preferred-source, browser-address-bar-color-changer) shipped the same payload to the same throwaway-style Netlify endpoint with the same hardcoded relay-secret string. That cluster shape — single author, multiple plugins, fresh-domain telemetry endpoint, all updated within minutes of each other — is exactly the pattern we look for as a possible early-stage supply-chain attack signal. The deeper read confirms it isn't: the endpoint is alive (Netlify Function returns HTTP 405 on GET, the /privacy page returns 200), the relay-secret is in PHP-only and never reaches the browser, and the JSON payload contains no credentials, hashes, options, or arbitrary content.
Posture critique (not a security finding): The Netlify auto-generated subdomain (startling-malasada-45aa0d) is owned by Mathew's Netlify account, not a hijack risk, but visually reads as throwaway. We'd suggest Mathew use a branded domain in future releases — and disclose the telemetry in the readme — to avoid future audits triggering on the same posture.
Audit retained for the record. No action required.
Affected plugins (5)
All plugins covered by this incident report. Combined exposure: 250 active installs across 5 slugs.
| Plugin | Active installs | Trunk version | wp.org status |
|---|---|---|---|
| Add as Preferred Source on Google | 100 | 1.2.1 | Open |
| Browser Address Bar Color Changer | 80 | 1.0.1 | Open |
| Disable Right Click & Content Copy Protection | 30 | 1.0.3 | Open |
| Image Zoom on Hover | 30 | 1.0.2 | Open |
| Announcement Notification Bar – Notification Top Bar & Sticky Call to Action Banner | 10 | 1.0.3 | Open |
Plugin version history
Every release on wp.org for this plugin. This audit found no malicious code; the version history is shown for reference.
-
Earlier 1 earlier release
-
1.0.1
-
-
1.1Audit baseline Last clean release before incident -
1.2Released after reopen PRT cleanup release — incident closed -
1.2.1Latest release Current release
Timeline
- 2025-07-28 —
mathewtwp.org account created - 2025-08-07 — first plugin published:
image-zoom-on-hover - 2025-08-25 —
disable-right-click-content-copy-protection - 2025-08-28 —
browser-address-bar-color-changer - 2025-09-09 —
add-as-preferred-source - 2025-11-19 —
announcement-notification-bar - 2026-05-05 07:35-07:41 UTC — synchronized release across all 5 plugins, each adding a per-plugin
class-{prefix}-deactivation-feedback.phpandclass-{prefix}-admin-notices.php
Actor footprint
| Plugin | Installs | Latest | Telemetry constant |
|---|---|---|---|
| add-as-preferred-source | 90 | 1.2 | AAPS_RELAY_SECRET |
| browser-address-bar-color-changer | 50 | 1.0.1 | BABC_RELAY_SECRET |
| image-zoom-on-hover | 30 | 1.0.2 | IZOH_RELAY_SECRET |
| disable-right-click-content-copy-protection | 20 | (post-repair) | (assumed, same pattern) |
| announcement-notification-bar | 10 | (post-repair) | (assumed, same pattern) |
All *_RELAY_SECRET constants are set to the literal string airtable-2026-mathew. All plugins POST to the same endpoint.
Code under review
The deactivation-feedback file (e.g. includes/class-izoh-deactivation-feedback.php) registers an admin script that injects a feedback modal into the Plugins screen, hooks wp_ajax_*_submit_feedback, and on submit calls:
wp_remote_post(
'https://startling-malasada-45aa0d.netlify.app/.netlify/functions/feedback',
array(
'headers' => array(
'Content-Type' => 'application/json',
'X-Relay-Secret' => IZOH_RELAY_SECRET,
),
'body' => wp_json_encode( $payload ),
'timeout' => 15,
)
);The $payload array contains:
$payload = array(
'reason' => sanitize_text_field( $_POST['reason'] ?? '' ),
'details' => sanitize_textarea_field( $_POST['details'] ?? '' ),
'admin_email' => sanitize_email( $_POST['admin_email'] ?? '' ), // user-fillable opt-in
'site_name' => get_bloginfo( 'name' ) ?: 'Unknown',
'site_url' => get_site_url() ?: 'Unknown',
'wp_version' => get_bloginfo( 'version' ) ?: 'Unknown',
'plugin_version' => $this->version ?: 'Unknown',
);No options, no user data, no credentials, no plugin content. Only the deactivating admin's site metadata + their typed reason + an opt-in email.
Live endpoint check
GET https://startling-malasada-45aa0d.netlify.app/ → 404
GET https://startling-malasada-45aa0d.netlify.app/.netlify/functions/feedback → 405 (Method Not Allowed)
GET https://startling-malasada-45aa0d.netlify.app/privacy → 200Endpoint is live and configured. Method 405 confirms the Netlify Function exists and only accepts the documented POST. The /privacy page exists, satisfying GDPR's basic disclosure requirement.
Hijack-indicator matrix
| Indicator | Result |
|---|---|
| Sole committer for ≥2 years? | n/a — Mathew has been the only committer since each plugin's first release |
| Sudden new committer before closure? | no — author unchanged across all 5 plugins |
| Author profile drift? | no — mathewt profile stable since 2025-07-28 |
| Code-level malware patterns? | no — no eval/base64-decode/file_put_contents/include of remote content |
| Outbound C2 / known bad domains? | no — single endpoint to a Netlify auto-name, payload contains no executable content |
| New SVN credentials before closure? | no — no closure; same author throughout |
| Plugin closed by wp.org? | no — all 5 are active |
Clean matrix → benign.
Why this isn't a supply-chain attack
1. The endpoint receives, doesn't serve. The plugin POSTs metadata; the response is discarded (wp_remote_post return value is not used). There is no pathway for the Netlify Function to return code that gets executed. 2. The "secret" is server-to-server. IZOH_RELAY_SECRET is a PHP constant only used in the HTTP header. The browser never sees it. If the Netlify Function were to be reverse-engineered, an attacker would only gain the ability to spam Mathew's feedback inbox — they cannot affect plugin behavior on user sites. 3. Trigger is one-shot, on deactivation only. Not on activation, not on a schedule, not on every page load. A site that deactivates the plugin sends one message and stops; a site that doesn't deactivate sends nothing. 4. No version pre-fix or fingerprint check. The module doesn't check whether the running site is "interesting" before phoning home (e.g. doesn't look for ecommerce, login forms, admin sessions). It's just metadata. 5. The pattern matches established premium-plugin SDKs (Freemius, Appsero, MonsterInsights). Mathew is doing the same thing with a less polished setup.
Comparable cases
- Audit #15 (content-egg) — different shape (historical PHP-object-injection chain) but same outcome: review-tier signal, deep-dive verdict benign with cleanup notes.
- Freemius SDK pattern — known-good telemetry shape that ships in 100s of wp.org plugins. Mathew's module is structurally identical.
- WPFactory cross-selling library FP class (memory:
project_wpfactory_cross_selling_fp_2026-04-27) — different actor, but same lesson: a vendor running their own opt-in admin telemetry is not by itself a security finding.
Reviewer notes
The reason this audit was opened was the actor-cluster shape, not any individual file pattern. WP Beacon's daily diff-review surfaces clusters where one author ships the same novel telemetry across multiple plugins on the same day — this is a high-value signal for early supply-chain attack detection (see the scroll-top / Benjamin / @milkitall case from audit #12 where a similar cluster was malicious). For Mathew, the cluster turned out to be a small developer adopting a feedback workflow. The audit is published as reassurance: site admins running any of the 5 plugins can see at a glance that the unfamiliar Netlify endpoint is intended, opt-in, and not a security risk.