CVE-2025-69016

Shortcodes and extra features for Phlox <= 2.17.14 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.17.14
PublishedDecember 27, 2025
Last updatedJanuary 5, 2026
Affected pluginauxin-elements
Research Plan
Unverified

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 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.php or includes/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) or auxin_dismiss_review_notice.
  • Parameter: id (The ID of the notice/option to update) and nonce (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)

  1. Registration: The plugin calls add_action( 'wp_ajax_auxin_dismiss_notice', array( $this, 'dismiss_notice' ) );. Note that wp_ajax_nopriv_ is likely not used, matching the "authenticated" requirement.
  2. Entry: A subscriber sends a POST request to admin-ajax.php with action=auxin_dismiss_notice.
  3. Nonce Verification: The handler calls check_ajax_referer( 'auxin_nonce', 'nonce' );.
  4. Authorization Gap: The handler fails to call current_user_can().
  5. 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.

  1. Login: Authenticate as a Subscriber.
  2. Navigate: Go to /wp-admin/profile.php. This ensures the WordPress admin environment is loaded.
  3. Extract Nonce: Use the browser_eval tool to retrieve the nonce from the global JavaScript object.
    • JS Variable: window.auxin_admin_vars?.nonce (or check for auxin_admin_vars.auxin_nonce).
  4. Action Check: Confirm the nonce is intended for the auxin_nonce action 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).

  1. Identify the target action: The most likely vulnerable function is auxin_dismiss_notice.
  2. Prepare Payload:
    • action: auxin_dismiss_notice
    • id: test_vulnerability_marker (This will create/update an option named auxin_dismissed_test_vulnerability_marker)
    • nonce: [Extracted in Step 4]
  3. Send Request: Use http_request to 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]

6. Test Data Setup

  1. Target Plugin: Install and activate auxin-elements version 2.17.14.
  2. User Creation:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    
  3. 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_marker should now exist in the wp_options table with the value 1.
  • Bypass: The action is completed despite the user only having subscriber permissions (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:

  1. Grep for AJAX handlers:
    grep -rn "wp_ajax_" /var/www/html/wp-content/plugins/auxin-elements/
    
  2. 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, or delete_post.
    • Lacks current_user_can.
  3. Common Candidate Actions:
    • auxin_update_post_order
    • auxin_metabox_ajax_save_post
    • auxin_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/
Research Findings
Static analysis — not yet PoC-verified

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

--- a/includes/admin/classes/class-auxin-admin-ajax.php
+++ b/includes/admin/classes/class-auxin-admin-ajax.php
@@ -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.