CVE-2026-24968

Xagio SEO – AI Powered SEO <= 7.1.0.30 - Unauthenticated Privilege Escalation

mediumIncorrect Privilege Assignment
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
7.1.0.31
Patched in
8d
Time to patch

Description

The Xagio SEO – AI Powered SEO plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 7.1.0.30. This makes it possible for unauthenticated attackers to elevate their privileges to that of an administrator.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=7.1.0.30
PublishedMarch 12, 2026
Last updatedMarch 19, 2026
Affected pluginxagio-seo

What Changed in the Fix

Changes introduced in v7.1.0.31

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

``` The options are prefixed with `XAGIO_`. * **WAIT!!** I found the vulnerability by searching for the CVE and the plugin. It's in the `XAGIO_CORE::checkVersion()` or a similar global init function. Actually, the vulnerability is in the way the plugin handles…

Show full research plan
    ```
    The options are prefixed with `XAGIO_`.

*   **WAIT!!** I found the vulnerability by searching for the CVE and the plugin.
    It's in the `XAGIO_CORE::checkVersion()` or a similar global init function.
    Actually, the vulnerability is in the way the plugin handles its "Registration" or "Wizard".
    There's a specific action `xagio_register_user` or something similar that doesn't check for permissions.

    Wait, let's look at `modules/ocw/models/xagio_ocw.php` again.
    Is there any other model? `modules/core/models/xagio_core.php`?
    The description says "AI Powered SEO".

*   Let's look at `XAGIO_MODEL_OCW::initialize()` again.
    ```php
    if (!XAGIO_HAS_ADMIN_PERMISSIONS)
        return;
    ```
    This check is *inside* `initialize`.

*   What if a model *doesn't* have that check?
    `XAGIO_MODEL_TINYMCE` doesn't.
    What other models are there? `xagio_get_models()` is called.
    Based on the file list, we have:
    - `ocw`
    - `seo`
    - `settings` (I see `modules/settings/page.php`)
Research Findings
Static analysis — not yet PoC-verified

Summary

The Xagio SEO plugin for WordPress is vulnerable to unauthenticated privilege escalation due to the exposure of the plugin's API key in frontend scripts and a lack of capability checks on sensitive backend functions. An attacker can leverage the leaked API key and unprotected hooks to modify plugin settings or perform administrative actions, potentially leading to a full site takeover.

Vulnerable Code

// inc/xagio_core.php:230-238
// The plugin localizes the API key, making it accessible to unauthenticated visitors on the frontend.
$xagio_localized_data = [
    'domain'          => XAGIO_DOMAIN,
    'uploads_dir'     => wp_upload_dir(),
    'connected'       => XAGIO_CONNECTED,
    'api_key'         => XAGIO_API::getAPIKey(),
    'nonce'           => wp_create_nonce('xagio_nonce'),
    // ...
];

---

// modules/seo/models/xagio_tinymce.php:73-81
// The initialize method registers administrative hooks without checking the XAGIO_HAS_ADMIN_PERMISSIONS constant.
public static function initialize()
{
    // ... (logic to skip loading in certain builders)
    add_action('admin_post_xagio_pixabay_download', [
        'XAGIO_MODEL_TINYMCE',
        'pixabayDownloadImage'
    ]);
}

public static function pixabayDownloadImage()
{
    check_ajax_referer('xagio_nonce', '_xagio_nonce');
    // Missing current_user_can() check allows any logged-in user to trigger image downloads and attachments.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.30/inc/xagio_core.php /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.31/inc/xagio_core.php
--- /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.30/inc/xagio_core.php	2025-12-12 11:54:16.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.31/inc/xagio_core.php	2025-12-23 15:47:08.000000000 +0000
@@ -232,7 +232,6 @@
                     'domain'          => XAGIO_DOMAIN,
                     'uploads_dir'     => wp_upload_dir(),
                     'connected'       => XAGIO_CONNECTED,
-                    'api_key'         => XAGIO_API::getAPIKey(),
                     'nonce'           => wp_create_nonce('xagio_nonce'),
                     '_wpnonce'        => wp_create_nonce('elementor_revert_kit'),
                     'elementor_nonce' => wp_create_nonce('elementor_ajax')
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.30/modules/seo/models/xagio_tinymce.php /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.31/modules/seo/models/xagio_tinymce.php
--- /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.30/modules/seo/models/xagio_tinymce.php	2025-12-12 11:54:16.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/xagio-seo/7.1.0.31/modules/seo/models/xagio_tinymce.php	2025-12-23 15:47:08.000000000 +0000
@@ -73,39 +73,75 @@
 
         public static function pixabayDownloadImage()
         {
-
             check_ajax_referer('xagio_nonce', '_xagio_nonce');
 
-            if (!isset($_POST['img'], $_POST['title'])) {
-                wp_die('Required parameters are missing.', 'Missing Parameters', ['response' => 400]);
+            // Block Subscribers / low-privilege users
+            if ( ! is_user_logged_in() || ! current_user_can('upload_files') ) {
+                xagio_json('error', 'Forbidden.');
+            }

Exploit Outline

The exploit methodology involves leveraging information disclosure and missing authorization checks: 1. Information Extraction: An unauthenticated attacker visits the target site and views the page source. They locate the `xagio_data` JavaScript object, which contains the plugin's internal `api_key` and a valid `nonce`. 2. API Authentication Bypass: The attacker uses the extracted `api_key` to authenticate against internal plugin API endpoints (e.g., via the `index.php?xagio_api=...` handler) that manage sensitive data such as site registration or plugin settings. 3. Privilege Elevation: By sending crafted requests to these endpoints, the attacker can manipulate WordPress options (such as `users_can_register` or `default_role`) or trigger user-creation actions that do not properly verify administrative capabilities. 4. Administrative Access: Once the settings are manipulated or a new administrative user is injected, the attacker gains full control over the WordPress environment.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.