CVE-2026-15097

Themify Builder <= 7.7.6 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'height_slider' Slider Module Field

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

Description

The Themify Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting via 'height_slider' Slider Module Field in all versions up to, and including, 7.7.6 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<=7.7.6
PublishedJuly 10, 2026
Last updatedJuly 11, 2026
Affected pluginthemify-builder

What Changed in the Fix

Changes introduced in v7.7.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill this request. I am prohibited from generating actionable exploitation plans or functional payloads for specific vulnerabilities. I can, however, provide a security analysis of the vulnerability and explain how to remediate the identified code flaw. ### Security Analysis of CVE-2026…

Show full research plan

I cannot fulfill this request. I am prohibited from generating actionable exploitation plans or functional payloads for specific vulnerabilities. I can, however, provide a security analysis of the vulnerability and explain how to remediate the identified code flaw.

Security Analysis of CVE-2026-15097

The vulnerability in Themify Builder (up to version 7.7.6) is a Stored Cross-Site Scripting (XSS) vulnerability. It occurs because the plugin fails to properly sanitize and escape user-supplied data before rendering it in the HTML output.

Vulnerable Code Path

The issue is located in the Slider module's template file: templates/template-slider.php.

In this file, the $fields_args['height_slider'] variable—which contains user-defined settings for the slider's height—is printed directly into a data-height attribute:

<div class="themify_builder_slider ... "
    ...
    data-height="<?php echo $fields_args['height_slider'] ?>"
    ...
>

Because the output is not passed through a context-aware escaping function like esc_attr(), an authenticated user with at least "Contributor" privileges can inject malicious HTML attributes or JavaScript. For example, if the height_slider field is set to a value like "><script>alert(1)</script>, the resulting HTML would break out of the attribute and execute the script:

<div class="themify_builder_slider" data-height=""><script>alert(1)</script>" ...>

Remediation

To fix this vulnerability, all user-controlled data must be escaped at the point of output. In WordPress, the esc_attr() function should be used when printing data inside HTML attributes.

Corrected Code:

<div class="themify_builder_slider ... "
    ...
    data-height="<?php echo esc_attr( $fields_args['height_slider'] ); ?>"
    ...
>

Additionally, implementing server-side sanitization when the builder data is saved (e.g., in ThemifyBuilder_Data_Manager::save_data) provides a secondary layer of defense.

For further information on securing WordPress plugins, you can consult the WordPress Plugin Handbook on Security and the OWASP XSS Prevention Cheat Sheet.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Themify Builder plugin is vulnerable to Stored Cross-Site Scripting (XSS) because it fails to properly sanitize and escape user-controlled data in the 'height_slider' field used by Slider and Gallery modules. Authenticated attackers with Contributor-level access or higher can inject arbitrary JavaScript into a page, which executes in the context of any user visiting the affected post.

Vulnerable Code

// templates/template-slider.php line 123
        data-height="<?php echo $fields_args['height_slider'] ?>"

---

// templates/template-gallery-slider.php line 58
                data-height="<?php echo isset($settings['horizontal']) && $settings['horizontal'] === 'yes' ? 'variable' : $settings['height_slider'] ?>"

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/themify-builder/7.7.6/classes/class-builder-data-manager.php /home/deploy/wp-safety.org/data/plugin-versions/themify-builder/7.7.7/classes/class-builder-data-manager.php
--- /home/deploy/wp-safety.org/data/plugin-versions/themify-builder/7.7.6/classes/class-builder-data-manager.php	2026-07-08 02:55:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/themify-builder/7.7.7/classes/class-builder-data-manager.php	2026-07-09 21:05:08.000000000 +0000
@@ -184,6 +184,10 ... @@
                 }
             }
             elseif(is_array($v)){
+                if ( $k === 'mod_settings' && isset( $arr['mod_name'] ) && is_string( $arr['mod_name'] ) ) {
+                    $v = self::sanitize_mod_settings( $arr['mod_name'], $v );
+                    $arr[ $k ] = $v;
+                }
                 if ($k === 'table_content' && isset($v['head'], $v['body'])) {
                     $arr[$k] = self::json_escape_table_content($v, $kses_filter);
                 } else {
@@ -198,6 +202,36 @@
     }
 
     /**
+     * Sanitize module settings that are rendered in HTML attributes or inline CSS.
+     */
+    private static function sanitize_mod_settings( string $mod_name, array $settings ):array {
+        if ( in_array( $mod_name, array( 'slider', 'gallery', 'testimonial-slider' ), true ) && isset( $settings['height_slider'] ) ) {
+            $settings['height_slider'] = themify_sanitize_slider_height( $settings['height_slider'] );
+        }
+        if ( $mod_name === 'map' ) {
+            if ( isset( $settings['b_width_map'] ) ) {
+                $settings['b_width_map'] = preg_replace( '/[^0-9.]/', '', (string) $settings['b_width_map'] );
+            }
+            if ( isset( $settings['b_style_map'] ) ) {
+                $settings['b_style_map'] = themify_sanitize_border_style( $settings['b_style_map'] );
+            }
+            if ( isset( $settings['w_map'] ) ) {
+                $settings['w_map'] = preg_replace( '/[^0-9.]/', '', (string) $settings['w_map'] );
+            }
+            if ( isset( $settings['h_map'] ) ) {
+                $settings['h_map'] = preg_replace( '/[^0-9.]/', '', (string) $settings['h_map'] );
+            }
+            if ( isset( $settings['w_map_unit'] ) ) {
+                $settings['w_map_unit'] = themify_sanitize_css_unit( $settings['w_map_unit'], '%' );
+            }
+            if ( isset( $settings['h_map_unit'] ) ) {
+                $settings['h_map_unit'] = themify_sanitize_css_unit( $settings['h_map_unit'] );
+            }
+        }
+        return $settings;
+    }

Exploit Outline

1. Login as a user with Contributor or higher permissions. 2. Create a new post or edit an existing one using the Themify Builder. 3. Add a 'Slider' or 'Gallery' module to the layout. 4. In the module configuration panel, locate the field responsible for setting the slider height (height_slider). 5. Input a payload that breaks out of the HTML attribute and executes JavaScript, for example: `"><script>alert(document.cookie)</script>`. 6. Save the page and view the published post. 7. The payload will execute because the template renders the raw string directly into the 'data-height' attribute of the module container.

Check if your site is affected.

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