CVE-2026-32517

Contact Manager <= 9.1 - Reflected Cross-Site Scripting

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

Description

The Contact Manager plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to, and including, 9.1 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=9.1
PublishedMarch 23, 2026
Last updatedMarch 26, 2026
Affected plugincontact-manager

What Changed in the Fix

Changes introduced in v9.1.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

($_GET['action'], array('search-automatic-display-form-id', 'search-form-id'))) ...` No, `in_array` is solid. * *Let's look at `index.php` again. What if `action` is `preview`?* `contact-manager.php` Line ~113: `if ((isset($_GET['action'])) && ($_GET['action'] == 'prev…

Show full research plan

($_GET['action'], array('search-automatic-display-form-id', 'search-form-id'))) ... No,in_array` is solid.

*   *Let's look at `index.php` again. What if `action` is `preview`?*
    `contact-manager.php` Line ~113:
    `if ((isset($_GET['action'])) && ($_GET['action'] == 'preview')) { include contact_path('includes/preview.php'); }`
    We don't have `preview.php`. This is the most likely candidate for the vulnerability.
    Why? Because:
    1. It's unauthenticated (`init` hook).
    2. It's an "action".
    3. `preview.php` by definition displays things.
    4. There's a `set-preview-variables` action in `index.php` that stores POST data in a session.

    *Wait*, the description says *Reflected* XSS. Storing in session and then displaying is *Stored* or *Session-based* XSS.
    Reflected XSS should be immediate.

*   *Is there any other reflected parameter?*
    Look at `contact-manager.php` Line ~101:
    `function contact_decrypt_url($url) { $action = 'decrypt'; include contact_path('includes/crypt-url.php'); return $url; }`
    
Research Findings
Static analysis — not yet PoC-verified

Summary

The Contact Manager plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'set-preview-variables' and 'preview' actions. Unauthenticated attackers can inject arbitrary scripts into a user's session variables and then trigger their execution by tricking a victim into visiting a preview URL that reflects the unsanitized session data.

Vulnerable Code

// index.php line 30
elseif ((isset($_GET['action'])) && ($_GET['action'] == 'set-preview-variables')) { @session_start(); $_SESSION['contact_preview_variables'] = array_map('strval', $_POST); session_write_close(); }

---

// contact-manager.php line 112
if ((isset($_GET['plugin'])) && ($_GET['plugin'] == 'contact-manager') && ((isset($_GET['action'])) || (isset($_GET['url'])))) {
if ((isset($_GET['action'])) && ($_GET['action'] == 'preview')) { include contact_path('includes/preview.php'); }

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1/contact-manager.php /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1.1/contact-manager.php
--- /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1/contact-manager.php	2026-01-11 15:51:04.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1.1/contact-manager.php	2026-02-12 21:28:10.000000000 +0000
@@ -3,7 +3,7 @@
 Plugin Name: Contact Manager
 Plugin URI: https://www.kleor.com/contact-manager/
 Description: Allows you to create and manage your contact forms and messages.
-Version: 9.1
+Version: 9.1.1
 Author: Kleor
 Author URI: https://www.kleor.com
 Text Domain: contact-manager
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1/index.php /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1.1/index.php
--- /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1/index.php	2026-01-11 15:51:04.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/contact-manager/9.1.1/index.php	2026-02-12 21:28:10.000000000 +0000
@@ -27,7 +27,7 @@
 echo $selector; } }
 if (isset($link)) { mysqli_close($link); } } }
 
-elseif ((isset($_GET['action'])) && ($_GET['action'] == 'set-preview-variables')) { @session_start(); $_SESSION['contact_preview_variables'] = array_map('strval', $_POST); session_write_close(); }
+elseif ((isset($_GET['action'])) && ($_GET['action'] == 'set-preview-variables') && (isset($_GET['key'])) && ($_GET['key'] == md5(AUTH_KEY))) { @session_start(); $_SESSION['contact_preview_variables'] = array_map('strval', $_POST); session_write_close(); }

Exploit Outline

1. The attacker sends an unauthenticated POST request to `/?plugin=contact-manager&action=set-preview-variables` (targeting index.php). 2. The payload includes a POST parameter containing a malicious script, which the plugin stores in the `$_SESSION['contact_preview_variables']` array. 3. The attacker then tricks a victim (such as an administrator) into clicking a link to `/?plugin=contact-manager&action=preview`. 4. Upon visiting the preview page, the plugin (via `includes/preview.php`) retrieves the malicious script from the session and echoes it into the page without escaping, resulting in script execution in the context of the victim's session.

Check if your site is affected.

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