SECURITY ADVISORY / 01

CVE-2026-8719 Exploit & Vulnerability Analysis

Complete CVE-2026-8719 security advisory with proof of concept (PoC), exploit details, and patch analysis for ai-engine.

ai-engine products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An authenticated user with Subscriber role (the lowest privilege tier in WordPress) can obtain and use an OAuth token to invoke admin-level MCP tools without holding administrator capabilities.

POST /wp-json/mwai/v1/mcp/authorize HTTP/1.1
Host: vulnerable-site.local
Content-Type: application/x-www-form-urlencoded
Cookie: wordpress_logged_in_..=subscriber_session_cookie

client_id=malicious-mcp-client&response_type=code&redirect_uri=http://attacker.local/callback&scope=admin&_mwai_nonce=<valid_nonce>

The Subscriber user receives a consent page and can mint an OAuth token. Once obtained, that token grants access to admin-level MCP operations (such as wp_create_user or file operations) that the Subscriber could never invoke directly in WordPress. The attacker observes HTTP 200 with a valid authorization code, exchanges it for a bearer token, and subsequently calls MCP endpoints with that token in the Authorization header. Each call executes with the privileges of the token-holder, not the Subscriber's actual WordPress role.

What the Patch Did

Before

if ( $this->oauth ) {
  $token_data = $this->oauth->validate_token( $token );
  if ( $token_data ) {
    // Set current user based on OAuth token
    wp_set_current_user( $token_data['user_id'] );
    $auth_result = 'oauth';

After

if ( $this->oauth ) {
  $token_data = $this->oauth->validate_token( $token );
  if ( $token_data ) {
    if ( !$this->oauth->user_can_authorize( $token_data['user_id'] ) ) {
      if ( $this->logging ) {
        error_log( '[AI Engine MCP] ❌ OAuth token rejected: user ' . $token_data['user_id'] . ' is not an administrator.' );
      }
      return false;
    }
    wp_set_current_user( $token_data['user_id'] );
    $auth_result = 'oauth';

The patch added a runtime capability gate: the user_can_authorize() method. This method is called every time an OAuth token is validated, ensuring the linked user currently holds administrator capabilities. If the check fails, the token is rejected and an error is logged. Additionally, the OAuth consent and token-submission endpoints now call user_can_authorize() at authorization time, preventing non-administrators from minting tokens in the first place:

if ( !$this->user_can_authorize( $user->ID ) ) {
  if ( $this->logging ) {
    error_log( '[AI Engine MCP OAuth] ❌ Non-admin user ' . $user->ID . ' tried to authorize client ' . $params['client_id'] );
  }
  $this->render_error_page( 'Only administrators can authorize MCP applications on this site.' );
  exit;
}

Root Cause

CWE-269: Improper Access Control (Broken Authorization). The vulnerability is a missing privilege check at the OAuth token consumption boundary. When a user presents a valid OAuth token (validated via signature or database lookup), the old code accepted it and set the current user based on $token_data['user_id'] without verifying that this user retained administrator privileges at the moment of use. The token itself was not scope-limited or capability-bound; it granted access to all MCP tools unconditionally. Since MCP tools are designed for admin-level operations (user creation, file manipulation, etc.), any user who could obtain a token could escalate to the capabilities implied by the MCP layer. The authorization endpoint (labs/mcp-oauth.php lines 386–395) was also missing a capability check, allowing non-admin users to reach the consent flow and mint tokens.

Why It Works

The load-bearing line is if ( !$this->oauth->user_can_authorize( $token_data['user_id'] ) ) in the token validation path. Without this check, a Subscriber's token would pass through and wp_set_current_user() would make all downstream code see the Subscriber as the current user — but the MCP layer would treat that user as if they held admin privileges (because it was checking the token, not the user's actual role). The engineer added two additional defenses: the same check at token-minting time (authorization endpoint) and the same check at token-submission time (token endpoint). Together, these block non-admins from ever obtaining a token and reject any pre-existing tokens from downgraded users. The logging in all three locations provides forensic visibility. Without the runtime check in the token validation path, a token minted before a user was demoted from Admin to Subscriber would still grant admin MCP access — a token-refresh or privilege-revocation scenario. Without the authorization-time checks, an attacker who discovers they can reach the OAuth endpoints would immediately mint a token. The patch applies the gate at every trust boundary.

Hardening Checklist

  • Apply capability gates at every auth boundary. Do not assume that validating a credential (token, session cookie, API key) is sufficient; verify the user's current permissions at the moment the credential is used via current_user_can( 'manage_options' ) or similar role-based checks. Tokens and sessions persist; roles and permissions do not.

  • Scope OAuth tokens to explicit capabilities at mint time. Do not design tokens to inherit all capabilities of the user who minted them. Implement a scope parameter in the authorization request and store granted scopes in the token payload. Verify scope at the tool invocation boundary, not user role.

  • Gate privileged OAuth endpoints. Treat the authorization endpoint, token endpoint, and scope-approval UI as privileged actions. Wrap these with wp_verify_nonce() and current_user_can( 'manage_options' ) before rendering consent or issuing tokens.

  • Log all auth failures and scope mismatches. Use error_log() with a machine-parseable format (e.g., [AI Engine MCP] ❌ ...) to record rejected tokens, failed capability checks, and unauthorized scope requests. Parse these logs weekly to detect token abuse.

  • Implement per-endpoint capability checks, not layer-wide role assumptions. Each MCP tool endpoint should call current_user_can() with a tool-specific capability (e.g., mcp_create_user, mcp_read_file) rather than assuming all authenticated users holding a token can invoke all tools.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-8719

Frequently asked questions about CVE-2026-8719

What is CVE-2026-8719?

CVE-2026-8719 is a security vulnerability identified in ai-engine. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-8719?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-8719. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-8719 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting ai-engine. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-8719?

CVE-2026-8719 affects ai-engine. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-8719?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for ai-engine.

What is the CVSS score for CVE-2026-8719?

The severity rating and CVSS scoring for CVE-2026-8719 affecting ai-engine is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.