Skip to content

WordPress validation-loop corruption, XML-RPC deserialization transport, and IdP assertion override (Sept 20 09:30Z wave)

Source: hourly offensive-security scan of GitHub Security Advisories, 2026-09-20 (wave published 2026-09-20T09:30Z, WPScan-style descriptions).

The recurring shapes this wave: a validation loop whose own bookkeeping is broken so the check always passes, deserialization reachable over a transport your fuzzer doesn't drive (XML-RPC, stored AJAX data), a nested composition path that skips the validation the parent path enforces, and an SSO plugin that ignores the identity-matching criterion the admin configured.

Advisory table

Product GHSA / CVE Boundary
Photo Gallery, Sliders, Proofing (NextGEN) < 4.5.0 GHSA-j73p-vqpx-6v96 / CVE-2026-81650 Archive extraction validates member extensions with a loop that reuses the loop counter as the validation state variable, so the check always passes → gallery-capability user writes arbitrary files into a web-accessible directory; RCE on hosts that execute them.
Photo Gallery (NextGEN) < 4.5.0 GHSA-w7wf-gqrx-wh54 / CVE-2026-81651 Gallery-save handler never verifies the caller owns the target gallery → any gallery-capability user overwrites any gallery's stored settings, including its filesystem path (the settings field that turns this into a storage-confusion primitive).
Photo Gallery (NextGEN) < 4.5.0 GHSA-f6f9-8ghp-5wg5 / CVE-2026-81652 Image-record read returns any image's stored metadata to Contributor+ — EXIF subset (camera, capture timestamp), internal checksums/IDs — data the plugin's own capability-gated path reserves to admins.
Photo Gallery (NextGEN) < 4.5.0 GHSA-vpjm-x6rh-jvwr / CVE-2026-81653 + GHSA-xcq4-7q66-rcp3 / CVE-2026-81654 Delete/copy/re-tag any image on the site; save site-wide image-sizing settings with only the gallery capability. Capability granted "manage my galleries" silently carries cross-tenant and global-config power.
Forminator Forms < 1.57.2.1 GHSA-h6cq-4ghp-3r32 / CVE-2026-87067 XML-RPC request value deserialized with no class restriction → forms-management permission (admin by default, but grantable to any role through Forminator's own settings) writes an arbitrary file → code execution. The entry point is xmlrpc.php, not the web form path.
Forminator Forms < 1.57.2.1 GHSA-xq3c-rrxv-22rc / CVE-2026-87068 Role validation applied by the ordinary form editor and ordinary form import is not applied when a registration form is nested inside an imported quiz → quiz importer publishes a live public form granting any role, including administrator, to any submitter. The identical artifact is refused through both sibling paths.
Unlimited Elements For Elementor < 2.0.20 GHSA-3wpx-h7q2-mv8g / CVE-2026-85017 AJAX action with no capability check deserializes attacker-controlled stored data → Subscriber-level arbitrary PHP object injection. Fix-history differential: 2.0.18–2.0.19 only raised the reachable role to Editor; full fix landed 2.0.20 — partial fixes change the auth context, not the sink.
SAML Single Sign On < 6.0.0 GHSA-c354-pg28-5955 / CVE-2026-82842 Plugin ignores the configured account-linking criterion and always resolves the incoming SSO identity by login name → an attacker who can have the site's IdP assert a chosen login name authenticates as any account, including administrator, without proving ownership.
TikTok < 1.4.2 GHSA-774v-j88v-3m84 / CVE-2026-92965 Sign-in callback runs on every request (not only the admin's session), performs no authorization, and loosely URL-matches so lookalike paths trigger it → any visitor makes the site redeem an attacker-chosen sign-in code against the advertising platform using the site's own credentials.
Meow Gallery < 5.5.5 GHSA-vwxr-fxpw-rxvm / CVE-2026-92422 Unauthenticated endpoint concatenates a user-supplied value into a shortcode string passed to the parser → arbitrary registered-shortcode execution and non-public gallery disclosure (adds to the Sept 19 do_shortcode()-primitive family).

Why this is worth an operator page

  • Validation loops can be structurally dead. NextGEN's archive-extension check reused the loop counter as the per-iteration validation result, so the final verdict was always "pass." Audit rule: on any multi-item validator (archive members, batch uploads, array fields), the test is mixed-content batches — one allowed item + one forbidden item in a single archive/array. Single-item tests cannot distinguish a working validator from a loop-corrupted one. This is the loop twin of the JetFormBuilder blocklist-omission lesson: test the set, not just the element.
  • XML-RPC is an un-fuzzed deserialization transport. Forminator's unrestricted object graph arrives via xmlrpc.php request values, not the form endpoints that get exercised. For any WordPress (or PHP) target with XML-RPC enabled, enumerate methods and pass serialized-object-shaped parameters to each — the same PHP-object-injection battery you run on POST params deserves its own XML-RPC pass. Pair with the forms-permission pre-condition check: Forminator's own settings can grant forms-management below administrator, so the CVSS's "admin only" framing understates reachable roles on sites using that feature.
  • Stored-data AJAX handlers inherit the writer's trust problem. Unlimited Elements deserializes stored plugin data through an unchecked AJAX action — the injection surface is whatever field any Subscriber can save. Sweep: for each AJAX action that reads plugin option/meta state into a deserializer, identify the lowest role that can write that state. Also note the partial-fix differential (2.0.18–2.0.19 raised the role instead of fixing the sink): fingerprint the exact minor version before concluding an advisory is patched, and re-test "fixed" versions for role-gated reachability of the same sink.
  • Composition paths skip the parent path's enforcement. Forminator's quiz import accepts a nested registration form the ordinary editor and importer both refuse. When a platform has a "container" artifact (import formats, quiz/builder nests, blocks-in-blocks, templates-of-templates), build the artifact through every containment path and diff the validation verdicts — same transport-parity axis as the Sept 19 alternate-surface page, but applied to nesting rather than route family. End-state is a public self-serve admin-maker: quiz-import permission → any visitor becomes administrator.
  • Configured security criteria that the code ignores. The SAML plugin's account-linking selector is admin-facing theater: the code always resolves by login name. Generalize the UsersWP email-assertion rule: after any SSO assertion, verify which field the server actually matches against (login, email, nameid, provider ID) by asserting different values per field in a lab IdP you control and observing which one binds. An attacker-controlled IdP assertion that binds on a guessable/enumerable login name = ATO up to admin. Decision-table proof: one lab user per field variant; record which assertion logs in as whom.
  • OAuth/OAuth-like code redemption is state-changing on the site's identity. TikTok's callback redeems any visitor's supplied code with the site's platform credentials. Sweep every "connect account" callback for: (a) does it run outside the connecting admin's session (on every page hit?), (b) does it path-match loosely, (c) whose credentials does it spend? Attacker-supplied code + site-side credential = CSRF against the integration, with the ad/account platform's own account linkage as the mutation.

Validation workflow (authorized scope only)

Lab installs, inert proofs

Disposable WordPress installs with the vulnerable plugin versions, synthetic users/roles/galleries, a lab IdP you control, and inert marker files. Never write real users' galleries, never grant real roles, never redeem third-party OAuth codes.

  1. Mixed-batch archive probe: build a lab ZIP with one permitted (.jpg) + one forbidden (.php-named, GIF-content) member; upload via the archive path as a gallery-capability lab role. Evidence: extracted file listing + served-vs-parsed behavior of the marker (no execution), fixed-version rejection of the same batch.
  2. Ownership matrix: gallery-capability users A and B; B attempts save/delete/copy/retag against A's gallery IDs, and saves the global sizing setting. Evidence: verdict table action × owner × result; record the filesystem-path settings field B can overwrite on A's gallery (point it at a second lab directory, never system paths).
  3. XML-RPC object-injection pass: on a lab install, fingerprint xmlrpc.php methods, submit serialized-object canaries (no POP chain, no file writes) to each parameter position, and compare deserialization errors/behavior against the same payload on POST params. Evidence: reachability table transport × method × verdict. Do not run a real POP chain.
  4. Nesting parity: create the role-granting registration form three ways — ordinary editor, ordinary import, nested-in-imported-quiz — as the quiz-importer lab role. Evidence: three-way verdict table; publish only in the lab, submit once from an anonymous session to confirm role mint, then delete.
  5. Assertion-field binding table: staging install + lab IdP; assert login-only, email-only, and mismatched pairs against a lab victim account. Evidence: which asserted field logs you in as whom. Never test against real tenants.
  6. Callback redemption test: instrument the connect-flow callback with a request log; load a lookalike URL as an anonymous session and record whether the redeem fires, whose credentials it uses, and whether the code came from the requester. Use only codes issued to your own integration test app.

Processed without publication

  • SmartLife follow-up GHSA-72pp-r64r-349h / CVE-2026-86554 — the /account/verify.serv email→account-ID oracle leg already published on the Sept 20 app-auth forgery page; marked processed there.
  • Import and export users and customers < 2.5.2 front-end import + CSV role-assignment skipping promote_users (GHSA-562f-rm3m-8jj6/CVE-2026-92541, GHSA-ghcr-hgpj-8xjg/CVE-2026-92540) — exact replay of the delegated-cap ≠ implied-cap deputy already on the Sept 19 alternate-surface page (WP Import Export Lite); no new axis. < 2.4.5 CSV-import SSRF (GHSA-h9fx-ggrg-2982/CVE-2026-16542) is high-priv wp_remote_get SSRF, existing axis.
  • SxDevOps 1.0/1.1 six-GHSA cluster (CVE-2026-93966/93967 command injection through paramiko exec_command/generate_host_task, CVE-2026-93968 UserSerializer privilege drift, CVE-2026-93969/93970 hardcoded default superuser/settings secrets, CVE-2026-93971 settings disclosure) — niche ops platform; the command-handler-into-SSH-exec axis is the Aug 6 agent tool-policy lesson restated; hardcoded-default-credential items noted, no validation workflow beyond "check default superusers on admin consoles."
  • SourceCodester Online Reviewer admin-panel SQLi trio (CVE-2026-93972/93973/93974) — detail-thin product-specific SQLi, existing class.
  • Kirki unsanitized SVG upload (CVE-2026-84223), Master Slider shortcode-attribute inline-script XSS with no fixed version (CVE-2026-14844 — worth re-fingerprinting in reports as an indefinitely-open Contributor XSS), Tripzzy unauth comment-delete + anonymous-issued-token admin actions (CVE-2026-87839/87840 — "token issued to any anonymous visitor" is the parameter-presence family restated), Sign-up Sheets CSRF nonce (CVE-2026-92410), Meow Gallery draft/private-post disclosure (CVE-2026-92423) — single-axis items covered by existing pages.

Reporting checklist

  • for loop-corrupted validators: exact validator, mixed-batch composition, extracted-vs-validated listing diff;
  • for deserialization: transport (xmlrpc method / AJAX action), writing-role for stored-data variants, exact fixed-version window, and the lowest role that reaches the sink after the "fix";
  • for nesting drift: all containment paths tried, verdict table, and the end-state capability the nested artifact grants;
  • for SSO binding: configured criterion vs actual matched field, per-field assertion decision table, lab IdP details redacted;
  • bounded impact language: object injection ≠ RCE without a demonstrated POP chain to a write sink; arbitrary file write ≠ RCE without handler execution proof; same-origin SVG ≠ session compromise without an inline-serving path.

Related pages: the Sept 20 app-auth forgery page (SmartLife twin), the Sept 19 alternate-surface page (transport-parity + deputy caps), the Sept 19 shortcode-primitive page (do_shortcode() execution family), and the Sept 16 identity-assertion page (SAML claim-binding decision tables).