Skip to content

Guard dismissed_wp_pointers against incorrect type stored in the database #12580

@benbowler

Description

@benbowler

Bug Description

A recent forum support topic raised a critical TypeError in our Email Reporting pointer. While pointers should be stored in the database as a string, if for any reason the value is changed to an array in the database (in the support case this was due to possible SQL injection) then the the value will be returned as an array.

WP Core guards against this by casting to (string) wherever dismissed_wp_pointers are queried from user meta:

https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-admin/includes/class-wp-internal-pointers.php#L80
https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-admin/plugin-editor.php#L351

We have two examples of unguarded user meta queries to dismissed_wp_pointers:

// Do not show if this pointer was already dismissed via core 'dismiss-wp-pointer'.
$user_id = get_current_user_id();
$dismissed_wp_pointers = get_user_meta( $user_id, 'dismissed_wp_pointers', true );
if ( $dismissed_wp_pointers ) {
$dismissed_wp_pointers = explode( ',', $dismissed_wp_pointers );
if ( in_array( self::SLUG, $dismissed_wp_pointers, true ) ) {
return false;
}
}

$user_id = get_current_user_id();
$dismissed_wp_pointers = get_user_meta( $user_id, 'dismissed_wp_pointers', true );
if ( $dismissed_wp_pointers ) {
$dismissed_wp_pointers = explode( ',', $dismissed_wp_pointers );
if ( in_array( self::SLUG, $dismissed_wp_pointers, true ) ) {
return false;
}
}

Both can have this guard added to avoid the stated issue.


Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance Criteria

  • Loading the WordPress dashboard (index.php) no longer fatals with a TypeError when dismissed_wp_pointers user meta is not a string.
  • The Email Reporting admin pointer and the view-only dashboard admin pointer both continue to hide themselves when the user has dismissed the matching pointer via core's dismiss-wp-pointer flow.

Implementation Brief

Backend

  • Update file includes/Core/Email_Reporting/Email_Reporting_Pointer.php use of the pointer meta to cast to string.

  • Update file includes/Core/Dashboard_Sharing/View_Only_Pointer.php use of the pointer meta to cast to string.

Test Coverage

  • Update file tests/phpunit/integration/Core/Email_Reporting/Email_Reporting_PointerTest.php

    • Add a case where dismissed_wp_pointers meta is stored as an array (via update_user_meta( $user_id, 'dismissed_wp_pointers', array( 'foo' ) )) and assert is_active( 'index.php' ) does not throw and returns the expected boolean.
  • Update file tests/phpunit/integration/Core/Dashboard_Sharing/View_Only_PointerTest.php

    • Add the same array-meta regression case for the view-only pointer's active_callback.

QA Brief

View-only user pointer

  • Set up Site Kit.
  • Using dashboard sharing, share access to non-admin users.
  • Log into the site with a non-admin, e.g. an editor user.
  • Verify that you see the View-only user WP pointer in the WordPress dashboard.
  • Update the dismissed_wp_pointers item in the _usermeta table for your user ID, and change it to an array, such as a:1:{i:0;s:3:"foo";}.
  • Reload the WordPress dashboard, verify that you still see the WP pointer and there's no error.

Email Reporting pointer

  • Follow the QAB of Implement the WordPress Pointer #11433 to see the Email Reporting WP pointer in the WordPress dashboard.
  • Update the dismissed_wp_pointers item in the _usermeta table for your user ID, and change it to an array, such as a:1:{i:0;s:3:"foo";}.
  • Reload the WordPress dashboard, verify that you still see the WP pointer and there's no error.

Changelog entry

  • Fix a fatal TypeError when dismissed_wp_pointers user meta contains an unexpected type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Medium priorityTeam MIssues for Squad 2Type: BugSomething isn't workingType: SupportSupport request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions