CVE-2026-11855: Unauthenticated Stored XSS in Simple Membership
Technical analysis of CVE-2026-11855, an unauthenticated stored cross-site scripting vulnerability in the Simple Membership WordPress plugin.
CVE-2026-11855: Unauthenticated Stored XSS in Simple Membership
Overview
I discovered an unauthenticated stored cross-site scripting vulnerability in the Simple Membership WordPress plugin.
The vulnerability affects Simple Membership versions earlier than 4.7.5 and has been assigned:
- CVE: CVE-2026-11855
- Vulnerability type: Unauthenticated Stored Cross-Site Scripting
- CWE: CWE-79
- CVSS: 8.8 — High
- Fixed version: 4.7.5
- WPVDB ID: 217cb606-a0f2-4427-9262-cfe1cc90474e
- Original Researcher: Duy Tran
- Submitter: Duy Tran
- Verification status: Verified
Summary
The Simple Membership plugin processes Stripe webhook requests through a publicly accessible endpoint.
In the affected version, the Stripe webhook signing secret is not generated automatically during installation and remains empty by default after plugin activation.
When no signing secret is configured, the webhook processing path accepts externally supplied webhook metadata without first confirming that the request originated from Stripe.
An unauthenticated attacker can therefore submit a forged webhook payload containing an attacker-controlled Stripe API version value.
The supplied value is stored in the WordPress database and subsequently rendered inside an administrator-facing notice without sufficient output encoding.
When an administrator opens the WordPress dashboard, the stored value is interpreted as HTML by the browser. This allows attacker-controlled JavaScript to execute automatically in the administrator’s browser context.
Expected Behavior
Webhook metadata should only be trusted after the authenticity and integrity of the webhook request have been verified.
Values originating from external webhook payloads should also be safely encoded immediately before being rendered inside administrator-facing HTML.
Actual Behavior
An unauthenticated attacker can submit a forged Stripe webhook payload that causes attacker-controlled data to be stored by WordPress.
The stored value is later included in an administrator notice without adequate output encoding.
Consequently, arbitrary JavaScript can execute when an authenticated administrator loads the WordPress dashboard.
Vulnerability Chain
The vulnerability results from the combination of two security failures.
1. Missing webhook authenticity verification
The plugin supports verification of Stripe webhook signatures when a signing secret has been configured.
However, the signing secret is empty in the default installation state.
In this state, the affected webhook path processes attacker-controlled requests without establishing that they were generated by Stripe.
This exposes externally supplied webhook metadata to the plugin’s internal processing logic.
2. Unsafe rendering of stored webhook data
An attacker-controlled value extracted from the webhook payload is stored in a WordPress option.
The stored value is later inserted into an administrative notice.
Because the value is not safely encoded for its final HTML output context, browser markup can be injected into the notice.
3. Automatic administrator-side execution
The malicious value is persistent.
The attacker does not need to convince the administrator to open an attacker-controlled URL or click a separate link.
The injected content is rendered when an administrator visits the affected WordPress administration page, causing the browser to execute the stored JavaScript in the context of the authenticated WordPress session.
Trust-Boundary Analysis
The vulnerable data flow can be summarized as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Unauthenticated Internet Request
|
v
Public Stripe Webhook Handler
|
v
Unverified Webhook Metadata
|
v
Persistent WordPress Option
|
v
Administrator Notice
|
v
JavaScript Execution in Administrator Context
The primary trust-boundary violation occurs when unauthenticated, externally supplied webhook metadata is accepted as trusted application state without cryptographic verification.
A second trust-boundary violation occurs when that stored value is rendered into an HTML document without context-appropriate output encoding.
Impact
Successful exploitation allows an unauthenticated attacker to execute arbitrary JavaScript in the browser of a logged-in WordPress administrator.
Depending on the administrator’s active session and installed components, attacker-controlled JavaScript may be able to:
- Read administrative pages accessible to the current user
- Obtain WordPress nonces exposed in dashboard pages
- Submit privileged requests using the administrator’s authenticated session
- Modify plugin or site configuration
- Create or modify users when the required authorization tokens are available
- Install or modify executable site content through available administrative functionality
- Establish persistent administrative access through a chained attack
The precise post-exploitation capabilities depend on the WordPress configuration, administrator privileges, available nonces, browser security controls, and installed plugins.
The vulnerability does not require the attacker to authenticate to WordPress.
Attack Preconditions
Exploitation requires the following conditions:
- A vulnerable Simple Membership version earlier than 4.7.5 is installed.
- The Stripe webhook signing secret is not configured.
- An attacker can access the public webhook processing endpoint.
- An administrator subsequently loads the affected WordPress administration interface.
The missing signing secret condition is particularly relevant because it occurs in the plugin’s default installation state unless the site administrator manually completes the Stripe webhook configuration.
Technical Validation
The issue was validated in a controlled local research environment using:
- WordPress: 7.0
- Simple Membership: 4.7.4
- PHP: 7.4.27
- Database: MariaDB 11
- Attacker authentication: None
- Victim role: Administrator
Testing confirmed that:
- A forged unauthenticated webhook request was accepted while the signing secret was empty.
- An attacker-controlled webhook value was stored persistently.
- The stored value reached an administrator-facing notice.
- The browser parsed the injected markup into the live DOM.
- JavaScript executed when the administrator loaded the WordPress dashboard.
Proof of Concept
The complete proof of concept is intentionally withheld during the coordinated disclosure period.
WPScan has scheduled publication of the public PoC for July 06, 2026, allowing additional time for site administrators to update vulnerable installations.
This section will be updated after the coordinated disclosure window ends.
Remediation
Administrators should update Simple Membership to version 4.7.5 or later.
As defense in depth, installations using Stripe should also:
- Configure the Stripe webhook signing secret
- Reject webhook requests when signature verification cannot be performed
- Avoid treating the absence of a signing secret as permission to process unsigned requests
- Escape all externally derived values at the point of HTML output
- Remove any suspicious values already stored by the affected webhook workflow
Webhook authentication and output encoding address separate security boundaries. Both protections should be applied independently.
Secure Design Recommendations
Fail closed when webhook verification is unavailable
If a webhook signing secret is missing, malformed, or unavailable, the plugin should reject the incoming webhook rather than process it without authentication.
A missing security control should not silently downgrade the endpoint into an unauthenticated mode.
Verify signatures before parsing trusted metadata
Webhook authenticity should be established before any externally supplied fields are accepted as trusted application state.
Verification should include the raw request body and the provider-supplied signature header according to Stripe’s webhook verification procedure.
Escape at the output boundary
All stored values originating from webhook requests should continue to be treated as untrusted.
Values rendered as text inside administrator notices should be escaped for their exact HTML context immediately before output.
Input sanitization alone should not replace context-sensitive output encoding.
Avoid persisting unnecessary external values
Externally controlled webhook metadata should only be stored when required for a clearly defined application purpose.
Reducing unnecessary persistence also reduces the number of paths through which untrusted data may later reach sensitive output contexts.
Disclosure Timeline
| Date | Event |
|---|---|
| 2026 | Vulnerability discovered and reproduced in a controlled environment |
| 2026 | Vulnerability submitted for coordinated disclosure |
| 2026 | Issue independently verified |
| 2026 | Simple Membership 4.7.5 released with a security fix |
| 2026-06-15 | CVE-2026-11855 publicly disclosed |
| 2026-06-15 | WPScan advisory published |
| 2026-07-06 | Scheduled publication date for the public proof of concept |
Additional dates may be added after the complete disclosure process concludes.
Research Credit
This vulnerability was independently discovered and reported by:
Duy Tran
- Original Researcher: Duy Tran
- Submitter: Duy Tran
- Research focus: WordPress plugin security, application security, and vulnerability research
References
- CVE-2026-11855
- WPScan Vulnerability Database entry:
217cb606-a0f2-4427-9262-cfe1cc90474e - Simple Membership version 4.7.5
- CWE-79: Improper Neutralization of Input During Web Page Generation
Responsible Disclosure Notice
The exploit request, executable payload, vulnerable source locations, and complete reproduction procedure have been withheld until the scheduled PoC publication date.
The information currently published is intended to document the vulnerability, credit the original research, explain the affected security boundaries, and encourage administrators to update without unnecessarily accelerating exploitation of unpatched systems.