- Vulnerability Background
What is this vulnerability?
- CVE-2025-13220 is a stored Cross-Site Scripting (XSS) issue in the Ultimate Member WordPress plugin.
- It occurs in the plugin’s shortcode rendering path for embedded media fields: YouTube, Vimeo, and Google Maps.
Why is it critical/important?
- Stored XSS allows attacker-controlled script to be persisted in the application and executed in the browser of any user who visits the affected page.
- In this case, an attacker with Contributor-level access or higher can inject malicious content into a page or profile field, and the payload executes whenever another user loads that page.
- This can lead to session theft, privilege escalation, content spoofing, and compromise of administrative accounts.
What systems/versions are affected?
- Ultimate Member – User Profile, Registration, Login, Member Directory, Content Restriction & Membership Plugin for WordPress
- All plugin versions up to and including 2.11.0 are affected.
- Technical Details
Root cause analysis
- The vulnerability is in
includes/core/um-filters-fields.php. - The plugin builds iframe markup by concatenating user-controlled values directly into the
srcattribute for:- YouTube embeds
- Vimeo embeds
- Google Maps embeds
- Examples from the vulnerable code:
- YouTube:
src="https://www.youtube.com/embed/' . $value . '" - Vimeo:
src="https://player.vimeo.com/video/' . $value . '" - Google Maps:
src="https://maps.google.it/maps?q=' . urlencode( $value ) . '&output=embed"
- YouTube:
Attack vector and exploitation conditions
- The attacker must be authenticated with Contributor access or above.
- The attacker can inject a crafted value into a shortcode attribute or a field value that the plugin later renders as an iframe.
- Because the plugin does not escape the final URL output, the attacker can manipulate the iframe markup and inject additional attributes or dangerous protocols.
- The payload is stored on the server and executed later in the browser of any user who views the affected page.
Security implications
- Stored XSS is a high-severity issue because it can affect multiple victims and persist over time.
- The vulnerable code path handles media embedding, which is commonly used in profile pages, directories, and content restriction pages—places where many users may visit.
- A successful exploit can be used to deliver secondary attacks such as CSRF, credential harvesting, or administrator session theft.
- Patch Analysis
What code changes were made?
- The patch modifies
includes/core/um-filters-fields.phpto apply output escaping on the generated iframe source URL. - Rather than concatenating raw
$valuedirectly into the HTML attribute, the code now constructs the full URL first and then passes it throughesc_url().
Specific fixes:
- YouTube:
- Old:
src="https://www.youtube.com/embed/' . $value . '" - New:
$value = 'https://www.youtube.com/embed/' . $value; ... src="' . esc_url( $value ) . '"
- Old:
- Vimeo:
- Old:
src="https://player.vimeo.com/video/' . $value . '" - New:
$value = 'https://player.vimeo.com/video/' . $value; ... src="' . esc_url( $value ) . '"
- Old:
- Google Maps:
- Old:
src="https://maps.google.it/maps?q=' . urlencode( $value ) . '&output=embed" - New:
$value = 'https://maps.google.it/maps?q=' . urlencode( $value ) . '&output=embed'; ... src="' . esc_url( $value ) . '"
- Old:
How do these changes fix the vulnerability?
esc_url()sanitizes the final URL before it is placed into thesrcattribute.- This prevents payloads that contain quote characters, event handlers, or unsafe protocol schemes from being interpreted as part of the HTML element.
- It enforces safe output encoding for URL context, which is the correct mitigation for this class of XSS.
Security improvements introduced
- The fix moves security control to output encoding rather than relying solely on the input parsing routines.
- It standardizes handling of dynamic URLs in iframe sources, reducing the risk of similar flaws elsewhere.
- It closes the gap between “trusted-looking” sanitized IDs/URLs and actual rendered HTML.
- Proof of Concept (PoC) Guide
Prerequisites for exploitation
- WordPress site with Ultimate Member plugin version 2.11.0 or earlier.
- Attacker account with Contributor-level access or higher.
- A page, profile field, or shortcode instance that renders one of the affected embed types.
Step-by-step exploitation approach
- Identify a field or shortcode parameter that accepts a YouTube, Vimeo, or Google Maps value.
- As an authenticated Contributor-level user, inject a malicious payload into that value.
- Save the content and visit the rendered page as a different user.
- Observe the execution of the injected JavaScript.
Example payload pattern
- If the plugin builds
src=".../$value"and does not escape$value, then$valuecan include a quote and an event handler:1">
- When rendered, the iframe tag becomes:
<iframe src="https://www.youtube.com/embed/1" ...>
- The browser then executes the injected
onloadhandler.
Expected behavior vs exploited behavior
- Expected: the field renders a valid embedded media iframe from YouTube, Vimeo, or Google Maps.
- Exploited: the field renders an iframe containing attacker-controlled markup, causing arbitrary JavaScript to execute in the victim’s browser.
How to verify the vulnerability exists
- Inspect the page source for iframe markup built from user-provided values.
- Look for raw concatenation of unescaped values in the
srcattribute. - Confirm that the attacker-controlled payload is present and that the browser executes it when the page loads.
- Verify that the plugin version is 2.11.0 or below.
- Recommendations
Mitigation strategies
- Update the Ultimate Member plugin to the patched version that includes these fixes.
- Restrict user privileges: limit Contributor access and ensure only trusted users can edit content or insert shortcode parameters.
- Review all shortcode-processing code for similar output-escaping gaps.
Detection methods
- Static analysis: search plugin code for direct concatenation of user-controlled values into HTML attributes, especially
src,href, andstyle. - Runtime monitoring: detect unexpected script execution from pages that render user-generated media embeds.
- Log review: monitor edits made by Contributor accounts to fields that map to embedded content.
Best practices to prevent similar issues
- Always apply context-appropriate escaping at the point of output.
- For URL attributes, use
esc_url()before injecting values into HTML attributes. - For HTML attribute values more generally, use
esc_attr()when appropriate. - Never assume that parser or normalization functions fully sanitize untrusted input.
- Treat shortcode attributes and stored field values as untrusted data.
- Apply the principle of least privilege to reduce the risk from lower-privileged accounts.