Fix: add per-post capability check to add_ignore AJAX handler#1712
Conversation
[Backport] Release v1.42.0
Any logged-in user could call edac_insert_ignore_data to dismiss issues
on posts they cannot edit. Add current_user_can('edit_post') check using
the same postid lookup pattern as the REST /dismiss-issue endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The initial fix only checked the first issue ID. A mixed-ID batch or a largeBatch request (which updates by object string site-wide) could still affect posts the user cannot edit. Now resolves all distinct postids for the full batch (or all posts sharing the same object in largeBatch mode) and gates on edit_post for every one before any UPDATE runs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR hardens the ChangesAuthorization and validation checkpoint
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request enhances security in the add_ignore AJAX handler by implementing a capability check that verifies edit_post permissions for all affected posts. The implementation accounts for both large batch updates based on object strings and smaller batches based on specific IDs. A review comment suggested removing a redundant array type cast on the database query results to align with existing coding patterns in the file.
The SELECT object query was running twice for largeBatch requests — once during the capability check and again in the execution block. Reuse $batch_object to avoid the redundant query. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@admin/class-ajax.php`:
- Around line 842-851: The permission check currently reads the authorized
object into $batch_object via $wpdb->get_var (using $valid_table and $first_id)
and builds $affected_post_ids, but later re-reads the object again before
performing the UPDATE which can cause a TOCTOU mismatch; modify the update path
to reuse the previously retrieved $batch_object (the value returned by
$wpdb->get_var and used to compute $affected_post_ids) instead of calling
$wpdb->get_var / re-querying the table again so the write operates on the exact
object set that was authorized.
- Around line 852-863: The handler currently proceeds as success when
$affected_post_ids is empty (e.g. all supplied $ids are stale), so add an
explicit check after building $affected_post_ids and before the permission loop:
if ( empty( $affected_post_ids ) ) call wp_send_json_error with the same '-2'
WP_Error used elsewhere to indicate "no matching items" (i.e., reject empty ID
lookups), ensuring you reference $ids, $affected_post_ids, wp_send_json_error
and preserve the existing permission checks using current_user_can.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e6748950-0717-4bdf-b923-d9ff65032843
📒 Files selected for processing (1)
admin/class-ajax.php
- Return -2 error when $affected_post_ids is empty (stale IDs should not succeed silently) rather than letting the foreach no-op and responding success - Remove redundant (array) cast; wpdb::get_col() always returns an array Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WP 7.0 added an `instanceof WP_Screen` guard to `get_current_screen()` (wp-admin/includes/screen.php). The anonymous-class mocks assigned to $GLOBALS['current_screen'] in EnqueueAdminTest and MetaBoxesTest no longer satisfy that check, so `Helpers::is_block_editor()` short-circuits to false and several enqueue/metabox tests fail. `WP_Screen` is final, so we can't subclass it. Use `set_current_screen()` to install a real screen and toggle the public `is_block_editor` property to simulate block-editor vs classic-editor contexts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… side effects set_current_screen() sets $hook_suffix, $typenow, and $taxnow, and fires the current_screen action. Since tearDown() only unsets $GLOBALS['current_screen'], those globals were left polluted between tests. WP_Screen::get() returns a proper WP_Screen instance (satisfying the WP 7.0 instanceof check) without any of those side effects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests: fix screen mocks for WP 7.0 (instanceof WP_Screen)
Summary
edac_insert_ignore_dataAJAX action had no capability check beyond nonce verification, allowing any logged-in user to dismiss accessibility issues on posts they cannot editcurrent_user_can('edit_post', $postid)for every post affected by the request — both the small-batch (per-ID lookup) andlargeBatch(object-string site-wide lookup) paths/dismiss-issueendpointDetails
Small batch path: resolves
DISTINCT postidfor all supplied IDs in one query and checksedit_poston each before anyUPDATEruns.largeBatch path: resolves the
objectstring from the first ID, then finds allDISTINCT postidvalues site-wide that share that object (matching exactly what theUPDATE … WHERE object = %swould touch), and checksedit_poston each.Any failing check returns
wp_send_json_error()with code-5 Permission Deniedbefore the database is written.Test plan
success: true)edit_poston the target post, sendedac_insert_ignore_datawith a valid nonce — should returnsuccess: false, code-5largeBatchrequest where the object string appears on posts the user cannot edit — should be rejected🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation