Audit #17 Benign
Show full summary
Suspect-shape but structurally unreachable — benign with one regression to flag. YARPP's version_info() matches the high-confidence catalog IOC unserialize_after_remote_call (@unserialize of wp_remote_post body, hardcoded endpoint, sslverify => false, no signature). The exact same shape that made content-egg's Admitad chain a 7-year latent RCE (audit #15). However, two independent failures make the chain dead code today: (1) the type-gate above the unserialize is always-true, blocking the call, and (2) the live yarpp.org/checkversion.php endpoint returns inert HTML rather than serialized PHP. The author is real and the domain is theirs. No active risk; one defensive regression worth flagging to the author.
Audit retained for the record. No action required.
Plugins under the same committer's SVN access
jeffparker holds push access to 1 plugin totalling 100k+ active installs.
Plugin version history
Every release on wp.org for this plugin. This audit found no malicious code; the version history is shown for reference.
-
1.0Audit baseline Last clean release before incident -
1.0.1Released after reopen PRT cleanup release — incident closed -
1.1Released Clean (post-cleanup) -
1.5Released Clean (post-cleanup) -
1.5.1Released Clean (post-cleanup) -
2.0.3Released Clean (post-cleanup) -
2.0.2Released Clean (post-cleanup) -
2.0.1Released Clean (post-cleanup) -
2.0Released Clean (post-cleanup) -
2.0.4Released Clean (post-cleanup) -
2.0.5Released Clean (post-cleanup) -
2.0.6Released Clean (post-cleanup) -
2.1Released Clean (post-cleanup) -
2.1.1Released Clean (post-cleanup) -
2.1.2Released Clean (post-cleanup) -
2.1.3Released Clean (post-cleanup) -
2.1.4Released Clean (post-cleanup) -
2.1.5Released Clean (post-cleanup) -
3.0b1Released Clean (post-cleanup) -
3.0b2Released Clean (post-cleanup) -
3.0b3Released Clean (post-cleanup) -
3.0b4Released Clean (post-cleanup) -
3.0b5Released Clean (post-cleanup) -
3.0b6Released Clean (post-cleanup) -
3.0b7Released Clean (post-cleanup) -
2.1.6Released Clean (post-cleanup) -
3.0.1Released Clean (post-cleanup) -
3.0.2Released Clean (post-cleanup) -
3.0.3Released Clean (post-cleanup) -
3.0.4Released Clean (post-cleanup) -
3.0.5Released Clean (post-cleanup) -
3.0.6Released Clean (post-cleanup) -
3.0.7b1Released Clean (post-cleanup) -
3.0.7b2Released Clean (post-cleanup) -
3.0.7Released Clean (post-cleanup) -
3.0.8b1Released Clean (post-cleanup) -
3.0.8b2Released Clean (post-cleanup) -
3.0.8b3Released Clean (post-cleanup) -
3.0.8b4Released Clean (post-cleanup) -
3.0.8Released Clean (post-cleanup) -
3.0.9Released Clean (post-cleanup) -
3.0.10Released Clean (post-cleanup) -
3.0.11Released Clean (post-cleanup) -
3.0.12Released Clean (post-cleanup) -
3.0.13Released Clean (post-cleanup) -
3.0.14b1Released Clean (post-cleanup) -
3.1b1Released Clean (post-cleanup) -
3.1Released Clean (post-cleanup) -
3.1.1Released Clean (post-cleanup) -
3.1.2b1Released Clean (post-cleanup) -
3.1.2Released Clean (post-cleanup) -
3.1.3b1Released Clean (post-cleanup) -
3.1.3b2Released Clean (post-cleanup) -
3.1.3b3Released Clean (post-cleanup) -
3.1.3Released Clean (post-cleanup) -
3.1.4b2Released Clean (post-cleanup) -
3.1.4b3Released Clean (post-cleanup) -
3.1.4b4Released Clean (post-cleanup) -
3.1.4Released Clean (post-cleanup) -
3.1.5Released Clean (post-cleanup) -
3.1.6Released Clean (post-cleanup) -
3.1.7Released Clean (post-cleanup) -
3.1.8Released Clean (post-cleanup) -
3.1.9Released Clean (post-cleanup) -
3.2b1Released Clean (post-cleanup) -
3.2b2Released Clean (post-cleanup) -
3.3Released Clean (post-cleanup) -
3.3.1Released Clean (post-cleanup) -
3.3.2Released Clean (post-cleanup) -
3.3.3b1Released Clean (post-cleanup) -
3.3.3b2Released Clean (post-cleanup) -
3.3.3Released Clean (post-cleanup) -
3.4b2Released Clean (post-cleanup) -
3.4b3Released Clean (post-cleanup) -
3.4b4Released Clean (post-cleanup) -
3.4b5Released Clean (post-cleanup) -
3.4b6Released Clean (post-cleanup) -
3.4b7Released Clean (post-cleanup) -
3.4b8Released Clean (post-cleanup) -
3.4b9Released Clean (post-cleanup) -
3.4b10Released Clean (post-cleanup) -
3.4RC1Released Clean (post-cleanup) -
3.4Released Clean (post-cleanup) -
3.4.1b1Released Clean (post-cleanup) -
3.4.1b2Released Clean (post-cleanup) -
3.4.1b3Released Clean (post-cleanup) -
3.4.1b4Released Clean (post-cleanup) -
3.4.1b5Released Clean (post-cleanup) -
3.4.1Released Clean (post-cleanup) -
3.4.2b1Released Clean (post-cleanup) -
3.4.3b1Released Clean (post-cleanup) -
3.4.3b2Released Clean (post-cleanup) -
3.4.3b3Released Clean (post-cleanup) -
3.4.3Released Clean (post-cleanup) -
3.4.4b1Released Clean (post-cleanup) -
3.4.4b2Released Clean (post-cleanup) -
3.4.4b3Released Clean (post-cleanup) -
3.4.2Released Clean (post-cleanup) -
3.4.4b4Released Clean (post-cleanup) -
3.5b4Released Clean (post-cleanup) -
3.5b5Released Clean (post-cleanup) -
3.5Released Clean (post-cleanup) -
3.5.1b1Released Clean (post-cleanup) -
3.5.2b1Released Clean (post-cleanup) -
3.5.1Released Clean (post-cleanup) -
3.5.2b2Released Clean (post-cleanup) -
3.5.2Released Clean (post-cleanup) -
3.5.3b1Released Clean (post-cleanup) -
3.5.3b2Released Clean (post-cleanup) -
3.5.2b3Released Clean (post-cleanup) -
3.5.3b4Released Clean (post-cleanup) -
3.5.3Released Clean (post-cleanup) -
3.5.4b2Released Clean (post-cleanup) -
3.5.4b3Released Clean (post-cleanup) -
3.5.4b4Released Clean (post-cleanup) -
3.5.4Released Clean (post-cleanup) -
3.5.5Released Clean (post-cleanup) -
3.5.6b1Released Clean (post-cleanup) -
3.5.6Released Clean (post-cleanup) -
3.6b1Released Clean (post-cleanup) -
3.6b2Released Clean (post-cleanup) -
3.6b3Released Clean (post-cleanup) -
3.6b4Released Clean (post-cleanup) -
3.6b5Released Clean (post-cleanup) -
3.6b6Released Clean (post-cleanup) -
4.0b8Released Clean (post-cleanup) -
4.0b9Released Clean (post-cleanup) -
4.0Released Clean (post-cleanup) -
4.0.1b1Released Clean (post-cleanup) -
4.0.1b2Released Clean (post-cleanup) -
4.0.1b3Released Clean (post-cleanup) -
4.0.1Released Clean (post-cleanup) -
3.0.2b1Released Clean (post-cleanup) -
4.0.2b2Released Clean (post-cleanup) -
4.0.2Released Clean (post-cleanup) -
4.0.3b1Released Clean (post-cleanup) -
4.0.3b2Released Clean (post-cleanup) -
4.0.3b4Released Clean (post-cleanup) -
4.0.3Released Clean (post-cleanup) -
4.0.4b1Released Clean (post-cleanup) -
4.0.4b2Released Clean (post-cleanup) -
4.0.4b3Released Clean (post-cleanup) -
4.0.4b4Released Clean (post-cleanup) -
4.0.4b5Released Clean (post-cleanup) -
4.0.4Released Clean (post-cleanup) -
4.0.5b1Released Clean (post-cleanup) -
4.0.5Released Clean (post-cleanup) -
4.0.6b1Released Clean (post-cleanup) -
4.0.6b2Released Clean (post-cleanup) -
4.0.6b3Released Clean (post-cleanup) -
4.0.6b4Released Clean (post-cleanup) -
4.0.7b1Released Clean (post-cleanup) -
4.0.6Released Clean (post-cleanup) -
4.0.7Released Clean (post-cleanup) -
4.0.8Released Clean (post-cleanup) -
4.1Released Clean (post-cleanup) -
4.1.1Released Clean (post-cleanup) -
4.1.2Released Clean (post-cleanup) -
4.2Released Clean (post-cleanup) -
4.2.1Released Clean (post-cleanup) -
4.2.2Released Clean (post-cleanup) -
4.2.3Released Clean (post-cleanup) -
4.2.4Released Clean (post-cleanup) -
4.2.5Released Clean (post-cleanup) -
4.3.1Released Clean (post-cleanup) -
4.3.2Released Clean (post-cleanup) -
4.3.3Released Clean (post-cleanup) -
4.3.4Released Clean (post-cleanup) -
4.3.5Released Clean (post-cleanup) -
4.3.6Released Clean (post-cleanup) -
4.4Released Clean (post-cleanup) -
4.2.6Released Clean (post-cleanup) -
4.5Released Clean (post-cleanup) -
4.6Released Clean (post-cleanup) -
5.0.0Released Clean (post-cleanup) -
5.0.1Released Clean (post-cleanup) -
5.1.0Released Clean (post-cleanup) -
5.1.1Released Clean (post-cleanup) -
5.1.2Released Clean (post-cleanup) -
5.1.3Released Clean (post-cleanup) -
5.1.4Released Clean (post-cleanup) -
5.1.5Released Clean (post-cleanup) -
5.1.6Released Clean (post-cleanup) -
5.1.9Released Clean (post-cleanup) -
5.1.8Released Clean (post-cleanup) -
5.2.0Released Clean (post-cleanup) -
5.2.1Released Clean (post-cleanup) -
5.2.2Released Clean (post-cleanup) -
5.3.0Released Clean (post-cleanup) -
5.4.0Released Clean (post-cleanup) -
5.5.0Released Clean (post-cleanup) -
5.6.0Released Clean (post-cleanup) -
5.7.0Released Clean (post-cleanup) -
5.8.0Released Clean (post-cleanup) -
5.9.0Released Clean (post-cleanup) -
5.10.0Released Clean (post-cleanup) -
5.10.1Released Clean (post-cleanup) -
5.10.2Released Clean (post-cleanup) -
3.2Released Clean (post-cleanup) -
3.2.2Released Clean (post-cleanup) -
3.2.2b1Released Clean (post-cleanup) -
3.2.3b3Released Clean (post-cleanup) -
3.2.1Released Clean (post-cleanup) -
3.2.3b2Released Clean (post-cleanup) -
3.2.1b1Released Clean (post-cleanup) -
3.2.1b2Released Clean (post-cleanup) -
3.2.1b4Released Clean (post-cleanup) -
3.2.3b1Released Clean (post-cleanup) -
3.2.1b3Released Clean (post-cleanup) -
3.2b4Released Clean (post-cleanup) -
3.2b3Released Clean (post-cleanup) -
5.11.0Released Clean (post-cleanup) -
5.12.0Released Clean (post-cleanup) -
5.13.0Released Clean (post-cleanup) -
5.14.0Released Clean (post-cleanup) -
5.15.1Released Clean (post-cleanup) -
5.15.2Released Clean (post-cleanup) -
5.15.3Released Clean (post-cleanup) -
5.16.1Released Clean (post-cleanup) -
5.16.0Released Clean (post-cleanup) -
5.17.0Released Clean (post-cleanup) -
5.18.1Released Clean (post-cleanup) -
5.18.2Released Clean (post-cleanup) -
5.19.0Released Clean (post-cleanup) -
5.20.0Released Clean (post-cleanup) -
5.21.0Released Clean (post-cleanup) -
5.22.0Released Clean (post-cleanup) -
5.23.0Released Clean (post-cleanup) -
5.1.7Released Clean (post-cleanup) -
5.24.0Released Clean (post-cleanup) -
5.25.0Released Clean (post-cleanup) -
5.26.0Released Clean (post-cleanup) -
5.27.0Released Clean (post-cleanup) -
5.27.1Released Clean (post-cleanup) -
5.27.2Released Clean (post-cleanup) -
5.27.3Released Clean (post-cleanup) -
5.27.4Released Clean (post-cleanup) -
5.27.5Released Clean (post-cleanup) -
5.27.6Released Clean (post-cleanup) -
5.27.7Released Clean (post-cleanup) -
5.27.8Released Clean (post-cleanup) -
5.30.1Released Clean (post-cleanup) -
5.30.2Released Clean (post-cleanup) -
5.30.3Released Clean (post-cleanup) -
5.30.4Released Clean (post-cleanup) -
5.30.5Released Clean (post-cleanup) -
5.30.6Released Clean (post-cleanup) -
5.30.7Released Clean (post-cleanup) -
5.30.8Released Clean (post-cleanup) -
5.30.9Released Clean (post-cleanup) -
5.30.10Released Clean (post-cleanup) -
5.30.11Latest release Current release
Suspect-shape but structurally unreachable — benign with one regression to flag. YARPP's version_info() matches the high-confidence catalog IOC unserialize_after_remote_call (@unserialize of wp_remote_post body, hardcoded endpoint, sslverify => false, no signature). The exact same shape that made content-egg's Admitad chain a 7-year latent RCE (audit #15). However, two independent failures make the chain dead code today: (1) the type-gate above the unserialize is always-true, blocking the call, and (2) the live yarpp.org/checkversion.php endpoint returns inert HTML rather than serialized PHP. The author is real and the domain is theirs. No active risk; one defensive regression worth flagging to the author.
Plugin
| Slug | yet-another-related-posts-plugin (YARPP) |
| Author | jeffparker |
| Active installs | 100,000 |
| Total downloads | 7,960,579 |
| Added | 2008-01-02 |
| Last update | 2024-11-11 (v5.30.11) |
| Closed? | No |
The chain (still in source as of v5.30.11)
classes/YARPP_Core.php:2099-2118:
public function version_info( $enforce_cache = false ) {
if ( ! $enforce_cache && false !== ( $result = $this->get_transient( 'yarpp_version_info' ) ) ) {
return $result;
}
$version = YARPP_VERSION;
$remote = wp_remote_post(
"https://yarpp.org/checkversion.php?format=php&version={$version}",
array( 'sslverify' => false ) // ← TLS regression (added 2021-10-12)
);
if ( is_wp_error( $remote ) || wp_remote_retrieve_response_code( $remote ) != 200
|| ! isset( $remote['body'] )
|| ! is_array( $remote['body'] ) ) { // ← always-true: gate the unserialize never reaches
$this->set_transient( 'yarpp_version_info', null, 60 * 60 );
return false;
}
if ( $result = @unserialize( $remote['body'] ) ) { // ← IOC sink, unreachable
$this->set_transient( 'yarpp_version_info', $result, 60 * 60 * 24 );
}
return $result;
}Three suspicious patterns compounding: 1. Hardcoded HTTP-fetch with sslverify => false — TLS cert validation disabled on transport. 2. responseType=php — explicitly asks for PHP-serialized payload. 3. Error-suppressed @unserialize of remote body, no allowlist, no integrity check.
That's the classic content-egg shape (audit #15). Latent PHP Object Injection if the chain were reachable — any gadget chain (Symfony, Composer, Magento, etc.) becomes RCE on the WordPress site if the operator endpoint or any TLS-MITM path is ever hostile.
Why it's unreachable
Gate failure 1: ! is_array($remote['body']) is always true
wp_remote_post() returns an associative array where body is always a string — that's been WordPress's WP_Http contract since WP 2.7 (2008). So is_array($remote['body']) is false, ! is_array(...) is true, and the early-return on the next line always fires. The @unserialize line is never executed.
$ php -r '$remote = ["body" => "anything"]; var_dump(is_array($remote["body"]));'
bool(false)This looks like a programmer typo — the author probably intended ! is_array($remote) (defending against null/error responses) but wrote ! is_array($remote['body']), which inverted the meaning and accidentally made the chain dead. Whatever the intent, the practical effect is that version_info() has been silently returning false on every call for ~6 years.
Gate failure 2: live endpoint returns inert HTML
Probed 2026-04-30:
$ curl -X POST "https://yarpp.org/checkversion.php?format=php&version=5.30.11"
HTTP/2 200
content-type: text/html
content-length: 41
<html><body><h1>200 OK</h1></html></body>41 bytes of HTML. Even if the is_array gate were fixed, the body isn't serialized PHP — @unserialize($html) returns false, set_transient is never called, function returns false. No exploitation path.
yarpp.org itself 301-redirects to https://yarpp.com/, which serves the active brand site. The checkversion.php URL was preserved (returns harmless 200) presumably for the long tail of installs still polling it.
Git-level forensics
| Date | Tag | Event |
|---|---|---|
| 2008-01-02 | 1.0 | Plugin shipped — original version_info() already does wp_remote_post(http://yarpp.org/checkversion.php?format=php) + @unserialize($remote['body']). Live exposure begins. |
| 2013-12-11 | 4.1-era | Function structure stable; ! isset($remote['body']) early-return added but no is_array typo gate yet. Still exposed. |
| ≤ 2020-05-11 | v5.1.4 | Typo gate ! is_array($remote['body']) already present. Chain becomes unreachable at some commit between 2013-12 and 2020-05 (more precise bisection skipped). |
| 2020-04-07 | v5.1.3 | URL switched from http:// to https:// (TLS introduced). |
| 2021-10-12 | v5.27.6 | Regression: sslverify => false added by jeffparker. TLS cert validation disabled. (Doesn't change the exploit picture because the chain is already unreachable, but it's a defensive regression worth noting.) |
| 2026-04-30 | v5.30.11 | Current state — chain unchanged, endpoint returns inert HTML. |
commit fd784c2 (2021-10-12) added sslverify => false to both the version_info() and optin_ping() calls. Likely the author was debugging a cert-chain issue from a host without proper CA bundles and committed the disable as a workaround.
Endpoint ownership
yarpp.org ↔ yarpp.com are both Jeff Parker's domains:
yarpp.org301 →yarpp.comyarpp.comserves an active YARPP brand site- wp.org profile
https://profiles.wordpress.org/jeffparker/shows display name "YARPP" — author identity matches domain
No "dangling-resource takeover" risk on the domain itself.
Threat model retrospective
If the typo gate had not existed (or were "fixed" by a future contributor), the exposure surface would have been:
- Anyone in a TLS-MITM position (since 2021-10-12, when
sslverify => falsewas added — before that, TLS was honored) yarpp.org's hosting provider, DNS provider, or any future buyer of the domain- Anyone who compromised the YARPP server hosting
checkversion.php
No public reports of in-the-wild exploitation. The gate has effectively neutralized the chain since v5.1.4 (May 2020) at the latest, and likely earlier.
Author intent assessment
jeffparker is the verified author of record (committer since 2013-09, member since [pre-2013]), with mitchoyoshitaka (Mitcho Erlewine, original co-author) as the prior committer 2012-2013, and mnelson4 as a brief 2021 contributor. No supply-chain-style changes — only routine maintenance. The code architecture is consistent with a 2008-era WordPress plugin that grew incrementally without a security retrofit. format=php was a standard PHP idiom of the era; the typo gate looks like an accidental defense rather than intentional gating.
Verdict
Benign — historical exposure (now closed). Same disposition as audit #15 (content-egg): suspect-shape chain matching a known IOC, with two independent failures making it unreachable. Difference from #15: YARPP's "gating" is an accidental typo rather than a deliberate throw, so the unreachability is fragile — a future contributor who "fixes" the always-true check could silently re-enable the sink.
Recommendations
To author (jeffparker): in priority order:
1. Switch the response format off ?format=php. Either change to ?format=json and use json_decode( wp_remote_retrieve_body($remote) ), or drop the version-check entirely (WordPress's own update API now handles this). Removes the IOC entirely. 2. Revert the sslverify => false regression added in v5.27.6 (commit fd784c2, 2021-10-12). If there's a TLS reason it was added, the right fix is updating the local CA bundle, not disabling validation. 3. Fix the always-true ! is_array($remote['body']) gate — but only after doing #1, otherwise this fix re-enables the IOC sink. The intent-likely guard is ! is_array($remote).
Cleanup status
cleanup_status = clean — no live exposure, no remediation needed for site owners. Author should land #1 + #2 above for hygiene; site owners running YARPP today are not at risk from this chain.