RTMKit <= 2.0.7 - Authenticated (Contributor+) Missing Authorization to Arbitrary Form Submission Access via 'entries_id' Parameter
Description
The RTMKit plugin for WordPress is vulnerable to Incorrect Authorization in all versions up to, and including, 2.0.7 This is due to the get_submission_content AJAX endpoint lacking a capability check to verify that a user has permission to access the requested form submission data. This makes it possible for authenticated attackers, with Contributor-level access and above, to view arbitrary form submissions from other users by iterating the entries_id parameter.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=2.0.7What Changed in the Fix
Changes introduced in v2.0.8
Source Code
WordPress.org SVNThis exploitation research plan focuses on **CVE-2026-5149**, an Incorrect Authorization vulnerability in the **RTMKit (RomeThemeKit)** plugin for WordPress. --- ### 1. Vulnerability Summary The RTMKit plugin (versions ≤ 2.0.7) registers an AJAX endpoint `get_submission_content` (likely within the…
Show full research plan
This exploitation research plan focuses on CVE-2026-5149, an Incorrect Authorization vulnerability in the RTMKit (RomeThemeKit) plugin for WordPress.
1. Vulnerability Summary
The RTMKit plugin (versions ≤ 2.0.7) registers an AJAX endpoint get_submission_content (likely within the SubmissionModule) that is intended to retrieve form submission data. The vulnerability arises because this endpoint fails to perform a capability check (e.g., current_user_can('manage_options')) or an ownership check on the requested data.
Authenticated users with Contributor-level permissions or higher can exploit this to view arbitrary form submissions—potentially containing sensitive PII (Personally Identifiable Information)—by iterating through the entries_id parameter.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
get_submission_content(Inferred AJAX action) - Vulnerable Parameter:
entries_id - Authentication: Authenticated (Contributor+)
- Required Header:
Content-Type: application/x-www-form-urlencoded - Nonce Action:
rtmkit_nonce(Required by the plugin's API pattern)
3. Code Flow
While the specific source for the SubmissionModule is truncated, the execution flow is grounded in the provided PluginApi.php and Plugin.php files:
- Registration: The
Pluginclass initializesSubmissionModule(Line 183 ofPlugin.php). - AJAX Hook: The module likely registers
wp_ajax_get_submission_content. - Vulnerable Handler: The handler function (likely
get_submission_content) is invoked. - Insecure Authorization: Unlike
PluginApi::get_content()(which checks formanage_options), the submission handler fails to verify if the current user should have access to the entry identified by$_POST['entries_id']. - Data Sink: The code queries the database for the submission corresponding to the ID and returns the content via
wp_send_json_success().
4. Nonce Acquisition Strategy
The plugin uses a nonce check: check_ajax_referer('rtmkit_nonce', 'nonce'). To obtain a valid nonce as a Contributor:
- Identify Trigger: The nonce is likely localized for the "System Panel" or the Form Submission management area in the admin dashboard.
- Setup Page: A Contributor can access the WordPress admin dashboard.
- Extraction:
- Navigate to the RTMKit dashboard or a page where the plugin's admin scripts are loaded (e.g.,
/wp-admin/admin.php?page=rtmkit). - Use
browser_evalto extract the nonce from the localized JavaScript object. - Inferred Variable: Based on the script handle
rtmkit-system-panel, the variable is likelyrtmkit_panel_varsor similar. - Command:
browser_eval("window.rtmkit_panel_vars?.nonce")or search forrtmkit_noncein the global scope.
- Navigate to the RTMKit dashboard or a page where the plugin's admin scripts are loaded (e.g.,
5. Exploitation Strategy
The goal is to demonstrate unauthorized access to a form submission created by another user (e.g., an Admin or a public visitor).
Step 1: Authenticate
Authenticate as a Contributor-level user.
Step 2: Nonce Retrieval
Fetch the nonce using the strategy in Section 4.
Step 3: Data Iteration
Send a series of POST requests to retrieve submissions.
- Request URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Body:
action=get_submission_content&nonce=[NONCE]&entries_id=[ID] - Example Payload (entries_id=1):
action=get_submission_content&nonce=a1b2c3d4e5&entries_id=1
Step 4: Analyze Response
A successful exploit will return a JSON object with success: true and the submission data in the data field, even if the user is not an admin.
6. Test Data Setup
- Form Creation: Create a form using the RTMKit Form widget (requires Elementor).
- Submission: Submit the form as an unauthenticated visitor or an Admin user with test data (e.g.,
email: admin-secret@example.com). - User Creation: Create a user with the Contributor role.
- Note ID: Identify the ID of the submission in the database (e.g., via
wp_rtmkit_submissionstable) to target it specifically.
7. Expected Results
- Unauthorized Access: The Contributor receives the full content of the submission (e.g., name, email, message) in the JSON response.
- HTTP 200 OK: The server returns a successful response instead of an "Access Denied" error or 403 status.
8. Verification Steps
After the HTTP request, verify the vulnerability using WP-CLI:
- Check Capability: Verify that the current user lacks the
manage_optionscapability:wp user cap list [CONTRIBUTOR_ID] - Compare Data: Verify that the data returned in the AJAX response matches the data stored in the database for that
entries_id:wp db query "SELECT * FROM wp_rtmkit_submissions WHERE id = [ID]"(Note: Table name is inferred).
9. Alternative Approaches
- Direct Parameter Manipulation: If
entries_idis not the only parameter, check forentry_idorsubmission_id. - GET Request: While
check_ajax_refererusually looks at$_REQUEST, try sending the payload viaGETifPOSTis blocked, as some plugins do not restrict the method. - ID Brute-forcing: If a specific ID is unknown, use a loop to iterate IDs from 1 to 500 to discover existing submissions.
Summary
The RTMKit plugin for WordPress is vulnerable to Incorrect Authorization in versions up to 2.0.7. The 'get_submission_content' AJAX endpoint fails to verify if the requesting user has administrative permissions, allowing authenticated attackers with Contributor-level access to view arbitrary form submissions by iterating the 'entries_id' parameter.
Vulnerable Code
// Inc/Core/Plugin.php // The plugin initializes the SubmissionModule which handles form data $this->modules = [ // ... 'submission' => \RTMKit\Modules\Submission\SubmissionModule::class, // ... ]; --- // Inferred logic within the SubmissionModule handler for 'get_submission_content' // The vulnerability occurs because the function lacks authorization checks public function get_submission_content() { check_ajax_referer('rtmkit_nonce', 'nonce'); // Missing: if (!current_user_can('manage_options')) { wp_die(); } $id = $_POST['entries_id']; // ... query database and return submission content }
Security Fix
@@ -2,6 +2,8 @@ namespace RTMKit\Core; +if (! defined('ABSPATH')) exit; + class PluginApi { @@ -55,14 +57,27 @@ public function get_content() { - check_ajax_referer('rtmkit_nonce', 'nonce'); + $nonce = isset($_POST['nonce']) + ? sanitize_text_field(wp_unslash($_POST['nonce'])) + : ''; + + if (! wp_verify_nonce($nonce, 'rtmkit_nonce')) { + die(__('Security check', 'rometheme-for-elementor')); + } + + // check_ajax_referer('rtmkit_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error('Access Denied.'); wp_die(); } - $path = sanitize_text_field($_POST['path']); - $menus = \RTMKit\Modules\Menu::instance()->get_menu_by_path($_POST['path']); + $path = isset($_POST['path']) + ? sanitize_text_field(wp_unslash($_POST['path'])) + : ''; + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $menus = \RTMKit\Modules\Menu::instance()->get_menu_by_path($path);
Exploit Outline
1. Authenticate to the WordPress dashboard as a user with Contributor-level privileges. 2. Identify and extract the 'rtmkit_nonce' value, which is commonly localized for scripts in the RTMKit dashboard or system panel. 3. Construct an AJAX POST request to '/wp-admin/admin-ajax.php' with the following body: 'action=get_submission_content&nonce=[NONCE]&entries_id=[TARGET_ID]'. 4. Send the request and capture the response. Because the server does not verify administrative capabilities for this action, it will return the full submission data for the specified ID, including any PII submitted via forms.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.