FAQ Builder AYS <= 1.8.2 - Unauthenticated Stored Cross-Site Scripting
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:NTechnical Details
<=1.8.2What Changed in the Fix
Changes introduced in v1.8.3
Source Code
WordPress.org SVNThis 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:
- At least one FAQ must be created.
- The "Allow users to ask questions" setting must be enabled for that FAQ (this is a per-FAQ or general setting).
3. Code Flow
- Submission: An unauthenticated user sends a POST request to
admin-ajax.phpwith the actionays_faq_send_question. - Processing: The handler (likely in
includes/class-faq-builder-ays.phpor a public class) retrieves$_POST['ays_faq_question']without applyingsanitize_text_field()orwp_kses(). - Storage: The unsanitized string is stored in the database, likely in a table named
wp_ays_faq_questions(inferred). - 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()orwp_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.
- Identify Shortcode: The plugin uses the shortcode
[ays_faq id="X"]. - Setup Page: Create a public page containing the shortcode for an existing FAQ.
- Variable Name: The plugin localizes data into a global JS object. Based on AYS naming conventions, this is likely
ays_faq_public_objorays_faq_ajax_obj. - Extraction:
- Navigate to the page with the shortcode.
- Use
browser_evalto 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 }
- 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.
- Identify FAQ ID: Use
wp_clito list FAQs and pick one:wp ays-faq list(if supported) orwp db query "SELECT id FROM wp_ays_faq_faqs LIMIT 1;". - Prepare Payload: Use a simple alert to prove execution:
<script>alert(document.domain)</script>. - 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_questionays_faq_question:<script>alert(document.domain)</script>ays_faq_id:[ID_FROM_STEP_1]ays_faq_name:Researcherays_faq_email:test@example.comnonce:[NONCE_FROM_STEP_4]
- URL:
- 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
- Create FAQ: Use the admin interface or SQL to ensure at least one FAQ exists.
- Enable Feature: Ensure the "Allow users to ask questions" option is checked in the FAQ settings.
- 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_requestshould 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
- Database Check: Verify the payload exists in the database.
wp db query "SELECT question FROM wp_ays_faq_questions WHERE author_name='Researcher';" - 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
nonceis not present in the localized script, try the request without thenonceparameter, as some versions may have omitted the check. - Different Action: If
ays_faq_send_questionfails, check the public JS files (public/js/faq-builder-ays-public.js) for the actual AJAX action name used in the$.ajaxcall. - Reflected XSS: Check if the
ays_create_faq_previewaction (found inadmin/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.