Orderable <= 1.20.0 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Plugin Installation
Description
The Orderable – WordPress Restaurant Online Ordering System and Food Ordering Plugin plugin for WordPress is vulnerable to unauthorized plugin installation due to a missing capability check on the 'install_plugin' function in all versions up to, and including, 1.20.0. This makes it possible for authenticated attackers, with Subscriber-level access and above, to install arbitrary plugins, which can lead to Remote Code Execution.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
This research plan outlines the steps required to analyze and exploit **CVE-2026-0974**, a missing authorization vulnerability in the **Orderable** WordPress plugin (<= 1.20.0) that allows Subscriber-level users to install arbitrary plugins, potentially leading to Remote Code Execution (RCE). --- …
Show full research plan
This research plan outlines the steps required to analyze and exploit CVE-2026-0974, a missing authorization vulnerability in the Orderable WordPress plugin (<= 1.20.0) that allows Subscriber-level users to install arbitrary plugins, potentially leading to Remote Code Execution (RCE).
1. Vulnerability Summary
The Orderable plugin contains an AJAX handler or function named install_plugin (likely within an admin-facing class) that performs plugin installation tasks. The vulnerability exists because this function fails to verify if the requesting user possesses the install_plugins or manage_options capability. While the function may be intended for admin-only setup wizards or extensions, it is registered via wp_ajax_, making it accessible to any authenticated user, including those with the Subscriber role.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
orderable_install_plugin(inferred from plugin slug and function name) - Vulnerable Parameter:
slug(the slug of the plugin to be installed from the WordPress.org repository). - Authentication: Authenticated, Subscriber role or higher.
- Preconditions:
- Plugin version <= 1.20.0 installed and active.
- A valid WordPress nonce (likely required by
check_ajax_referer).
3. Code Flow (Inferred)
- Registration: The plugin registers the AJAX handler in a setup or admin class:
add_action( 'wp_ajax_orderable_install_plugin', [ $this, 'install_plugin' ] ); - Entry Point: An authenticated user sends a POST request to
admin-ajax.phpwithaction=orderable_install_plugin. - Vulnerable Sink: The
install_pluginmethod is called. It likely uses the WordPressPlugin_Upgraderclass or theplugins_apito fetch and install a plugin. - Missing Check: The code likely checks a nonce using
check_ajax_referer( 'orderable_nonce', 'security' )but fails to callif ( ! current_user_can( 'install_plugins' ) ) { wp_die(); }.
4. Nonce Acquisition Strategy
To exploit this as a Subscriber, we must find where the orderable plugin localizes its administrative nonces.
- Identify the Script: Look for
wp_localize_scriptcalls in the codebase involving "orderable". - Create Page: As an admin, create a public post/page with an Orderable-related shortcode (e.g.,
[orderable_categories]) if the script is only loaded on specific pages. - Subscriber Login: Log in as a Subscriber user.
- Extraction:
- Navigate to the WordPress Dashboard (Subscribers can access
wp-admin/index.phpby default). - Open the browser console or use
browser_eval. - Search for localized objects. Common names in this plugin:
orderable_admin,orderable_vars, ororderable_settings. - Target JavaScript Variable:
window.orderable_admin?.nonceorwindow.orderable_admin?.install_nonce(inferred).
- Navigate to the WordPress Dashboard (Subscribers can access
5. Exploitation Strategy
The goal is to install a plugin that provides further control (e.g., wp-file-manager or a "Code Snippets" plugin) to achieve RCE.
Step 1: Login
- Authenticate as a Subscriber user.
Step 2: Nonce Retrieval
- Use
browser_navigatetowp-admin/or a page containing an Orderable shortcode. - Execute
browser_evalto extract the nonce.
Step 3: Trigger Plugin Installation
- Send a POST request to
admin-ajax.php. - Payload:
(Note: Parameter names likePOST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=orderable_install_plugin&slug=wp-file-manager&security=[EXTRACTED_NONCE]securityornonceandslugmust be verified by grepping theinstall_pluginfunction source).
Step 4: Activation (If applicable)
- If the plugin is installed but not activated, check if there is a corresponding
orderable_activate_pluginaction with the same missing authorization vulnerability.
6. Test Data Setup
- Install Orderable plugin version 1.20.0.
- Create a user with the Subscriber role:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Ensure the site can reach
wordpress.orgfor plugin downloads.
7. Expected Results
- The
admin-ajax.phpresponse should return a success status (e.g.,{"success":true}or a HTML success message from the Upgrader). - The file system should now contain the directory
/wp-content/plugins/wp-file-manager/.
8. Verification Steps
- Check Plugin Existence:
wp plugin is-installed wp-file-manager - Check Plugin Status:
wp plugin list --status=inactive(to see if it was installed but needs activation). - Log File Review: Check for
Plugin_Upgraderlogs inwp-content/upgrade/.
9. Alternative Approaches
- Search for other Slugs: If
wp-file-manageris blocked or fails, trywp-terminalorhello-dolly(as a benign PoC). - Remote ZIP (if supported): Check if
install_pluginaccepts aurlparameter instead of just aslug. If it accepts a URL, provide a link to a malicious plugin ZIP hosted on a remote server for immediate RCE. - Action Name Guessing: If
orderable_install_pluginfails, grep the source for anyadd_actioncalls that include the stringinstall.grep -r "install" . | grep "wp_ajax"
Grep Commands for Initial Research
# Find the vulnerable function definition
grep -r "function install_plugin" .
# Find the AJAX action registration
grep -r "wp_ajax_" . | grep "install_plugin"
# Find where the nonce is created
grep -r "wp_create_nonce" . | grep -i "install"
# Find the JS variable used for localization
grep -r "wp_localize_script" . -A 5
Summary
The Orderable plugin for WordPress fails to implement a capability check on its 'install_plugin' AJAX handler. This allows authenticated users with Subscriber-level permissions or higher to install any arbitrary plugin from the WordPress repository, potentially leading to full site compromise via Remote Code Execution (RCE).
Vulnerable Code
// Likely located in an admin class within the Orderable plugin // Example: includes/admin/class-orderable-admin.php add_action( 'wp_ajax_orderable_install_plugin', [ $this, 'install_plugin' ] ); public function install_plugin() { // Nonce check may exist, but authorization check is missing check_ajax_referer( 'orderable_nonce', 'security' ); // VULNERABILITY: No check for current_user_can( 'install_plugins' ) $slug = isset( $_POST['slug'] ) ? sanitize_text_field( $_POST['slug'] ) : ''; include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; $api = plugins_api( 'plugin_information', array( 'slug' => $slug, 'fields' => array( 'sections' => false ) ) ); $upgrader = new Plugin_Upgrader( new WP_Ajax_Upgrader_Skin() ); $result = $upgrader->install( $api->download_link ); if ( is_wp_error( $result ) ) { wp_send_json_error(); } wp_send_json_success(); }
Security Fix
@@ -XX,6 +XX,10 @@ public function install_plugin() { check_ajax_referer( 'orderable_nonce', 'security' ); + if ( ! current_user_can( 'install_plugins' ) ) { + wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'orderable' ) ) ); + } + $slug = isset( $_POST['slug'] ) ? sanitize_text_field( $_POST['slug'] ) : ''; if ( empty( $slug ) ) { wp_send_json_error();
Exploit Outline
1. Authenticate to the WordPress site as a user with the Subscriber role. 2. Access the WordPress dashboard and extract the required AJAX nonce (typically localized in a script object like 'orderable_admin' or 'orderable_vars') from the page source or browser console. 3. Construct a POST request to /wp-admin/admin-ajax.php using the action 'orderable_install_plugin'. 4. Include the 'slug' parameter set to a plugin that facilitates code execution (e.g., 'wp-file-manager' or 'code-snippets') and the extracted 'security' nonce. 5. Upon successful execution, the plugin will be installed into the /wp-content/plugins/ directory, where the attacker can then attempt to activate it (if a similar authorization bypass exists for activation) to gain remote control.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.