weDocs: AI Powered Knowledge Base, Docs, Documentation, Wiki & AI Chatbot <= 2.3.0 - Missing Authorization to Authenticated (Subscriber+) Data Migration via wedocs_migrate_betterdocs_to_wedocs AJAX Action
Description
The weDocs: AI Powered Knowledge Base, Docs, Documentation, Wiki & AI Chatbot plugin for WordPress is vulnerable to Missing Authorization in versions up to and including 2.3.0. This is due to a missing capability check on the do_migration() function registered as the wedocs_migrate_betterdocs_to_wedocs AJAX action, which performs no nonce verification via check_ajax_referer() and no capability check via current_user_can() before executing sensitive operations. This makes it possible for authenticated attackers, with Subscriber-level access and above, to trigger a full BetterDocs-to-weDocs data migration, creating and modifying 'docs' custom post type entries with attacker-controlled titles, updating site options, and deactivating the BetterDocs and BetterDocs Pro plugins via deactivate_plugins().
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.3.1
Source Code
WordPress.org SVN# Research Plan: CVE-2026-12729 - weDocs Missing Authorization in Data Migration ## 1. Vulnerability Summary The **weDocs** plugin (up to version 2.3.0) contains a missing authorization vulnerability in its data migration utility. Specifically, the function `do_migration()`, which is registered to …
Show full research plan
Research Plan: CVE-2026-12729 - weDocs Missing Authorization in Data Migration
1. Vulnerability Summary
The weDocs plugin (up to version 2.3.0) contains a missing authorization vulnerability in its data migration utility. Specifically, the function do_migration(), which is registered to the wedocs_migrate_betterdocs_to_wedocs AJAX action, fails to implement any capability checks (current_user_can()) or nonce verification (check_ajax_referer()).
This allows any authenticated user, including those with Subscriber-level permissions, to trigger a migration process that can:
- Deactivate the
better-docsandbetter-docs-proplugins. - Create or modify entries in the
docscustom post type. - Update site options.
- Inject attacker-controlled titles into the documentation.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
wedocs_migrate_betterdocs_to_wedocs - HTTP Method:
POST - Authentication: Authenticated (Subscriber+)
- Parameters:
action:wedocs_migrate_betterdocs_to_wedocs- (Inferred) The migration likely processes posts with the
betterdocspost type. The attacker may need to control content within that post type or provide specific parameters to the migration function if it accepts raw input.
- Preconditions: The attacker must have a valid session cookie for a Subscriber-level user.
3. Code Flow
- Entry Point: A
POSTrequest is sent toadmin-ajax.phpwithaction=wedocs_migrate_betterdocs_to_wedocs. - Hook Registration (Inferred in
includes/admin/class-migration.phpor similar):add_action( 'wp_ajax_wedocs_migrate_betterdocs_to_wedocs', [ $this, 'do_migration' ] ); - Vulnerable Function: The
do_migration()function is executed. - Missing Checks: The function proceeds immediately to data processing without calling:
check_ajax_referer()current_user_can( 'manage_options' )
- Impact Sinks:
deactivate_plugins()is called to disable BetterDocs.wp_insert_post()orwp_update_post()is called to create/modifydocspost types.update_option()is called to record migration status.
4. Nonce Acquisition Strategy
According to the vulnerability description, the do_migration() function "performs no nonce verification via check_ajax_referer()". Therefore, no nonce is required to exploit this specific vulnerability.
If a nonce were required, it would likely be localized via wp_localize_script in an admin-only script. However, because the check is explicitly stated as missing, the exploit can proceed with just a Subscriber session.
5. Exploitation Strategy
Step 1: Authentication
Obtain a session cookie for a Subscriber-level user.
Step 2: Trigger Migration
Send a POST request to trigger the migration. Since this is a migration tool, it likely scans for existing BetterDocs content.
Request Details:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencodedCookie: [Subscriber Cookies]
- Body:
action=wedocs_migrate_betterdocs_to_wedocs
Step 3: Verification of Disruption
The primary indicator of success is the deactivation of the BetterDocs plugin and the creation/transformation of documentation posts.
6. Test Data Setup
To demonstrate the full impact (creation of docs and deactivation), the following environment must be prepared:
- weDocs 2.3.0 installed and active.
- BetterDocs (free version) installed and active.
- Create a few posts of type
betterdocswith distinct titles (e.g., "Secret BetterDoc Title"). - Create a Subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password.
7. Expected Results
- HTTP Response: 200 OK, likely with a JSON body indicating success or number of items migrated.
- Plugin State: The BetterDocs plugin should be deactivated in the WordPress admin.
- Post Data: New posts of type
docs(weDocs type) should appear in the database, mirroring or modifying the previous BetterDocs entries. - Site Options: Options like
wedocs_migration_done(inferred) may be set inwp_options.
8. Verification Steps
After sending the HTTP request, use WP-CLI to verify the state changes:
- Check Plugin Status:
wp plugin list --status=inactive | grep better-docs - Check Created Documentation:
wp post list --post_type=docs - Verify Subscriber Ownership (if applicable):
Check if the migration script incorrectly assigned ownership of the new docs to the user who triggered the migration.
9. Alternative Approaches
If the action=wedocs_migrate_betterdocs_to_wedocs requires additional parameters (e.g., specific post IDs or steps):
- Fuzzing Parameters: Try adding
step=1,limit=50, orpost_ids[]=1. - Error-Based Discovery: Observe if the AJAX response returns errors like "Missing parameter X" to refine the payload.
- Source Code Search: If the environment allows, search for the string
do_migrationin the plugin directory to find the exact expected$_POSTkeys.grep -rn "function do_migration" /var/www/html/wp-content/plugins/wedocs/
Summary
The weDocs plugin for WordPress contains a missing authorization vulnerability in its data migration utility. Authenticated attackers with Subscriber-level access or higher can trigger the 'wedocs_migrate_betterdocs_to_wedocs' AJAX action to perform sensitive operations, including deactivating the BetterDocs plugin and modifying documentation custom post types, due to missing capability checks and nonce verification.
Vulnerable Code
// In the plugin's migration handler class, typically registered in an admin context // No capability check or nonce verification is performed add_action( 'wp_ajax_wedocs_migrate_betterdocs_to_wedocs', [ $this, 'do_migration' ] ); /** * Migrates data from BetterDocs to weDocs */ public function do_migration() { // Vulnerability: Missing check_ajax_referer() // Vulnerability: Missing current_user_can( 'manage_options' ) $migration_data = $_POST['data']; // Sensitive operation: deactivating competitors deactivate_plugins( [ 'better-docs/better-docs.php', 'better-docs-pro/better-docs-pro.php' ] ); // Sensitive operation: modifying documentation posts // ... migration logic involving wp_insert_post() or update_option() ... wp_send_json_success( [ 'message' => __( 'Migration completed', 'wedocs' ) ] ); }
Security Fix
@@ -10,6 +10,12 @@ * @return void */ public function do_migration() { + check_ajax_referer( 'wedocs_migration_nonce', 'security' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( [ 'message' => __( 'Permission denied', 'wedocs' ) ] ); + } + $step = isset( $_POST['step'] ) ? sanitize_text_field( $_POST['step'] ) : ''; switch ( $step ) {
Exploit Outline
To exploit this vulnerability, an attacker needs a valid session for any authenticated user (such as a Subscriber). The methodology is as follows: 1. **Authentication**: Log into the WordPress site as a Subscriber-level user. 2. **Request Construction**: Construct a POST request to the `/wp-admin/admin-ajax.php` endpoint. 3. **Payload**: Set the 'action' parameter to 'wedocs_migrate_betterdocs_to_wedocs'. Since the function lacks nonce verification and capability checks, no security token is required. 4. **Execution**: Send the request. The server will execute the `do_migration()` function, which triggers the deactivation of the BetterDocs and BetterDocs Pro plugins and initiates the data migration process, potentially overwriting or creating documentation entries with attacker-influenced data.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.