Joli Table Of Contents is a WordPress plugin that automatically builds a table of contents for posts and pages, used on around 7,000 active sites. During security testing a stored Cross-Site Scripting flaw was found and assigned CVE-2025-15694: the plugin does not sanitize and escape some of its settings before printing them back on its own admin page. A high-privilege user (Administrator) can store JavaScript in the headings_overflow setting that then executes on the plugin’s settings screen — including in setups where administrators are not allowed to post raw HTML, such as WordPress Multisite. The issue affects versions 2.0.0 – 2.8.0 and is fixed in 2.8.1.

CVECVE-2025-15694
Joli Table Of Contents 2.0.0 – 2.8.0
All Time145 580
Active installations7 000+
Publicly PublishedSeptember 3, 2026
Last UpdatedSeptember 3, 2026
ResearcherKrugov Artyom
OWASP TOP-10A03:2021 – Injection (Cross-Site Scripting)
CWECWE-79
PoCYes
ExploitNo
Referencehttps://www.cve.org/CVERecord?id=CVE-2025-15694
https://wpscan.com/vulnerability/9ebaf1aa-eb8b-4c62-bbd0-07918503fbf1/
Plugin Security Certification by CleanTalkNot safe
Logo of the pluginJoli Table Of Contents plugin logo

Join the community of developers who prioritize security. Highlight your plugin in the WordPress catalog.

PSC by Cleantalk

Timeline

August 22, 2025Plugin testing and vulnerability detection in the Joli Table Of Contents have been completed
August 22, 2025I contacted the author of the plugin and provided a vulnerability PoC with a description and recommendations for fixing
August 13, 2026The vendor released the patched version 2.8.1
September 3, 2026Registered CVE-2025-15694

Discovery of the Vulnerability

While auditing the settings handling of the Joli Table Of Contents plugin, I found that several options saved from the plugin’s General settings tab are stored and later printed back into the admin page without proper output escaping. One of them is the headings_overflow option, submitted as the joli_table_of_contents_settings[headings_overflow] parameter. The value is written straight into an HTML attribute on the settings form, so a payload that closes the attribute injects executable markup that is stored in the database and runs every time the settings page is opened — a persistent (Stored) XSS. Because the sink is the plugin’s own admin screen, the payload fires in the browser of any administrator who visits that page.

Understanding of Stored XSS attacks

Stored (persistent) Cross-Site Scripting saves the attacker’s payload on the server so it is served automatically to whoever opens the affected page. This case requires an Administrator account, which is why the CVSS score is Low on a standard single site — an administrator there can already post raw HTML through the unfiltered_html capability. The risk becomes real on WordPress Multisite and hardened installations, where site administrators do not hold unfiltered_html: the missing escaping lets them bypass that restriction and store JavaScript that runs in the context of the network, and it also widens the blast radius of a single compromised admin session or a CSRF-style trick against an administrator.

Exploiting the Stored XSS Vulnerability

To reproduce the vulnerability on an affected version (2.0.0 – 2.8.0):

  • Log in as an Administrator and open the Joli TOC plugin tab.
  • Go to the General settings section.
  • Insert the XSS payload into the joli_table_of_contents_settings[headings_overflow] parameter (the Headings overflow field) and save the settings.
  • Reopen the settings page and move the mouse over the field to trigger the payload.

PoC payload placed in the headings_overflow setting:

123123"onmouseover='alert(777)'

After saving, the value is reflected into the settings form and the injected onmouseover handler executes alert(777) in the admin context. In a real attack the harmless alert() would be replaced with code that creates a rogue network administrator, plants a backdoor, or exfiltrates session data — running silently whenever the plugin settings page is loaded.

Recommendations for Improved Security

To mitigate CVE-2025-15694:

  • Update Joli Table Of Contents to version 2.8.1 or later immediately.
  • Sanitize settings on input and escape them on output with esc_attr() / esc_html() so option values can never break out of their HTML context.
  • Do not rely on the administrator role as a trust boundary for HTML — escape output even for high-privilege users, especially on Multisite where unfiltered_html is disallowed.
  • Add CSRF nonces to settings forms so options cannot be changed by a forged request against a logged-in administrator.
  • Implement a strong Content Security Policy (CSP) to block inline JavaScript execution.
  • Deploy a Web Application Firewall to filter XSS payloads before they reach the application.

To prevent this type of attack, follow our methods of XSS prevention.

By addressing Stored XSS vulnerabilities like CVE-2025-15694 early, WordPress site owners and plugin developers can protect administrators and entire networks from account takeover. Stay vigilant, stay secure.

#WordPressSecurity #StoredXSS #JoliTOC #WebsiteSafety #StayProtected

Use CleanTalk solutions to improve the security of your website

Krugov Artyom
CVE-2025-15694 – Joli Table Of Contents – Stored XSS – PoC

Artyom Krugov

Cybersecurity Specialist with 4 years of hands-on experience in web application and WordPress security. Holder of the OSCP+ certification and author of 80+ publicly disclosed CVEs affecting WordPress plugins and themes. Specialized in vulnerability research, penetration testing, website incident response, malware removal, and security hardening of production environments. Experienced in identifying and validating high-impact vulnerabilities in WordPress plugins, themes, and custom web applications, as well as providing practical remediation guidance to improve overall security posture. Strong background in web application security, source code review, vulnerability assessment, exploit validation, and post-compromise recovery of infected websites.

Visit Author's Website

See all posts by krugov-artyom

Leave a Reply

Your email address will not be published. Required fields are marked *