• Resolved joshbour

    (@joshbour)


    Hello,

    Thanks for this great plugin. I have noticed issues with Yoast that end up in infinite recursion.
    I did some debugging, I’m attaching the log from the debug and Claude’s summary from the log. As a note, if I disable Yoast the plugin works fine.

    Summary: When authenticating via API key, ewpa_authenticate_api_key() (hooked on determine_current_user) calls user_can($user, 'manage_options') inside ewpa_validate_api_key(). On sites where another plugin filters map_meta_cap and calls wp_get_current_user() from within that filter (e.g. Yoast SEO’s WPSEO_Register_Capabilities::map_meta_cap_for_seo_manager), this re-enters determine_current_user before the user is resolved, causing unbounded recursion. PHP aborts with a fatal (Xdebug catches it at 512 frames; without Xdebug it runs to memory exhaustion). The REST/MCP endpoint returns HTTP 500.

    Environment: WordPress (PHP, Xdebug enabled). Reproduced with Yoast SEO and WPML String Translation active. MCP endpoint: /wp-json/mcp/mcp-adapter-default-server.

    Faulty code path:

    • enable-abilities-for-mcp/includes/auth.php:140ewpa_validate_api_key() called from the determine_current_user filter
    • enable-abilities-for-mcp/includes/auth.php:61get_userdata(1)
    • enable-abilities-for-mcp/includes/auth.php:62user_can( $user, 'manage_options' ) ← triggers map_meta_cap, which re-enters wp_get_current_user()

    Debug log (part):

    [10-Jun-2026 09:29:14 UTC] PHP Fatal error:  Uncaught Error: Xdebug has detected a possible infinite loop, and aborted your script with a stack depth of '512' frames in /var/www/html/wp-includes/plugin.php:173
    Stack trace:
    #0 /var/www/html/wp-content/plugins/wpml-string-translation/classes/class-wpml-st-user-fields.php(221): apply_filters('wpml_translate_...', false)
    #1 /var/www/html/wp-includes/class-wp-hook.php(343): WPML_ST_User_Fields->translate_get_user_metadata(NULL, 1, 'wp_c02nscl_capa...', true)
    #2 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(NULL, Array)
    #3 /var/www/html/wp-includes/meta.php(664): apply_filters('get_user_metada...', NULL, 1, 'wp_c02nscl_capa...', true, 'user')
    #4 /var/www/html/wp-includes/meta.php(602): get_metadata_raw('user', 1, 'wp_c02nscl_capa...', true)
    #5 /var/www/html/wp-includes/user.php(1282): get_metadata('user', 1, 'wp_c02nscl_capa...', true)
    #6 /var/www/html/wp-includes/class-wp-user.php(912): get_user_meta(1, 'wp_c02nscl_capa...', true)
    #7 /var/www/html/wp-includes/class-wp-user.php(887): WP_User->get_caps_data()
    #8 /var/www/html/wp-includes/class-wp-user.php(185): WP_User->for_site(0)
    #9 /var/www/html/wp-includes/pluggable.php(109): WP_User->init(Object(stdClass))
    #10 /var/www/html/wp-includes/pluggable.php(84): get_user_by('id', 1)
    #11 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(61): get_userdata(1)
    #12 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(140): ewpa_validate_api_key('Kn9WWtJz2DkjuMO...')
    #13 /var/www/html/wp-includes/class-wp-hook.php(341): ewpa_authenticate_api_key(false)
    #14 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
    #15 /var/www/html/wp-includes/user.php(3826): apply_filters('determine_curre...', false)
    #16 /var/www/html/wp-includes/pluggable.php(70): _wp_get_current_user()
    #17 /var/www/html/wp-content/plugins/wordpress-seo/admin/capabilities/class-register-capabilities.php(92): wp_get_current_user()
    #18 /var/www/html/wp-includes/class-wp-hook.php(343): WPSEO_Register_Capabilities->map_meta_cap_for_seo_manager(Array, 'manage_options')
    #19 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(Array, Array)
    #20 /var/www/html/wp-includes/capabilities.php(879): apply_filters('map_meta_cap', Array, 'manage_options', 1, Array)
    #21 /var/www/html/wp-includes/class-wp-user.php(790): map_meta_cap('manage_options', 1)
    #22 /var/www/html/wp-includes/capabilities.php(1021): WP_User->has_cap('manage_options')
    #23 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(62): user_can(Object(WP_User), 'manage_options')
    #24 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(140): ewpa_validate_api_key('Kn9WWtJz2DkjuMO...')
    #25 /var/www/html/wp-includes/class-wp-hook.php(341): ewpa_authenticate_api_key(false)
    #26 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
    #27 /var/www/html/wp-includes/user.php(3826): apply_filters('determine_curre...', false)
    #28 /var/www/html/wp-includes/pluggable.php(70): _wp_get_current_user()
    #29 /var/www/html/wp-content/plugins/wordpress-seo/admin/capabilities/class-register-capabilities.php(92): wp_get_current_user()
    #30 /var/www/html/wp-includes/class-wp-hook.php(343): WPSEO_Register_Capabilities->map_meta_cap_for_seo_manager(Array, 'manage_options')
    #31 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(Array, Array)
    #32 /var/www/html/wp-includes/capabilities.php(879): apply_filters('map_meta_cap', Array, 'manage_options', 1, Array)
    #33 /var/www/html/wp-includes/class-wp-user.php(790): map_meta_cap('manage_options', 1)
    #34 /var/www/html/wp-includes/capabilities.php(1021): WP_User->has_cap('manage_options')
    #35 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(62): user_can(Object(WP_User), 'manage_options')
    #36 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(140): ewpa_validate_api_key('Kn9WWtJz2DkjuMO...')
    #37 /var/www/html/wp-includes/class-wp-hook.php(341): ewpa_authenticate_api_key(false)
    #38 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
    #39 /var/www/html/wp-includes/user.php(3826): apply_filters('determine_curre...', false)
    #40 /var/www/html/wp-includes/pluggable.php(70): _wp_get_current_user()
    #41 /var/www/html/wp-content/plugins/wordpress-seo/admin/capabilities/class-register-capabilities.php(92): wp_get_current_user()
    #42 /var/www/html/wp-includes/class-wp-hook.php(343): WPSEO_Register_Capabilities->map_meta_cap_for_seo_manager(Array, 'manage_options')
    #43 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(Array, Array)
    #44 /var/www/html/wp-includes/capabilities.php(879): apply_filters('map_meta_cap', Array, 'manage_options', 1, Array)
    #45 /var/www/html/wp-includes/class-wp-user.php(790): map_meta_cap('manage_options', 1)
    #46 /var/www/html/wp-includes/capabilities.php(1021): WP_User->has_cap('manage_options')
    #47 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(62): user_can(Object(WP_User), 'manage_options')
    #48 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(140): ewpa_validate_api_key('Kn9WWtJz2DkjuMO...')
    #49 /var/www/html/wp-includes/class-wp-hook.php(341): ewpa_authenticate_api_key(false)
    #50 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
    #51 /var/www/html/wp-includes/user.php(3826): apply_filters('determine_curre...', false)
    #52 /var/www/html/wp-includes/pluggable.php(70): _wp_get_current_user()
    #53 /var/www/html/wp-content/plugins/wordpress-seo/admin/capabilities/class-register-capabilities.php(92): wp_get_current_user()
    #54 /var/www/html/wp-includes/class-wp-hook.php(343): WPSEO_Register_Capabilities->map_meta_cap_for_seo_manager(Array, 'manage_options')
    #55 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(Array, Array)
    #56 /var/www/html/wp-includes/capabilities.php(879): apply_filters('map_meta_cap', Array, 'manage_options', 1, Array)
    #57 /var/www/html/wp-includes/class-wp-user.php(790): map_meta_cap('manage_options', 1)
    #58 /var/www/html/wp-includes/capabilities.php(1021): WP_User->has_cap('manage_options')
    #59 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(62): user_can(Object(WP_User), 'manage_options')
    #60 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(140): ewpa_validate_api_key('Kn9WWtJz2DkjuMO...')
    #61 /var/www/html/wp-includes/class-wp-hook.php(341): ewpa_authenticate_api_key(false)
    #62 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
    #63 /var/www/html/wp-includes/user.php(3826): apply_filters('determine_curre...', false)
    #64 /var/www/html/wp-includes/pluggable.php(70): _wp_get_current_user()
    #65 /var/www/html/wp-content/plugins/wordpress-seo/admin/capabilities/class-register-capabilities.php(92): wp_get_current_user()
    #66 /var/www/html/wp-includes/class-wp-hook.php(343): WPSEO_Register_Capabilities->map_meta_cap_for_seo_manager(Array, 'manage_options')
    #67 /var/www/html/wp-includes/plugin.php(205): WP_Hook->apply_filters(Array, Array)
    #68 /var/www/html/wp-includes/capabilities.php(879): apply_filters('map_meta_cap', Array, 'manage_options', 1, Array)
    #69 /var/www/html/wp-includes/class-wp-user.php(790): map_meta_cap('manage_options', 1)
    #70 /var/www/html/wp-includes/capabilities.php(1021): WP_User->has_cap('manage_options')
    #71 /var/www/html/wp-content/plugins/enable-abilities-for-mcp/includes/auth.php(62): user_can(Object(WP_User), 'manage_options')
    ... and it keeps going
Viewing 1 replies (of 1 total)
  • Plugin Author fabiomontenegro1987

    (@fabiomontenegro1987)

    Thanks for the detailed debug log — that trace made the root cause immediately clear.

    The issue is in ewpa_authenticate_api_key(), which hooks determine_current_user. Inside it, user_can() fires map_meta_cap, and Yoast’s map_meta_cap_for_seo_manager callback calls wp_get_current_user() unconditionally — re-entering the determine_current_user filter before the user is resolved, which loops back into our function.

    The fix is a static re-entry guard (static $resolving = false) that detects the second entry and returns immediately, allowing Yoast’s callback to complete, then the outer call finishes authentication normally.

    This is shipped in v2.0.16 — updating the plugin should resolve it completely. Let me know if you run into anything else.

Viewing 1 replies (of 1 total)

You must be logged in to reply to this topic.