Skip to content

[2.x] fix(notifications): scope notification queries to the authenticated user#4441

Merged
imorland merged 1 commit into
2.xfrom
im/fix-notification-idor
Mar 14, 2026
Merged

[2.x] fix(notifications): scope notification queries to the authenticated user#4441
imorland merged 1 commit into
2.xfrom
im/fix-notification-idor

Conversation

@imorland

@imorland imorland commented Mar 14, 2026

Copy link
Copy Markdown
Member

Summary

Fixes an IDOR vulnerability in NotificationResource where the Update endpoint fetched notifications by ID using an unscoped query, allowing any authenticated user to read the contents of any other user's notification by guessing its sequential ID.

  • The Index (listing) endpoint was correctly scoped via NotificationRepository — this is not affected
  • The Update path falls through to AbstractDatabaseResource::find(), which uses an unscoped Eloquent query — this is the affected path
  • The write side (marking as read) was separately protected by ownership enforcement in ReadNotificationHandler; the exposure was read-only

Fix: override scope() in NotificationResource to filter all queries by user_id = actor->id, ensuring any lookup returns 404 for notifications belonging to other users.

Introduced in: #3971 (the JSON:API rewrite). This did not exist in 1.x — the old UpdateNotificationController exclusively dispatched ReadNotificationHandler, which always enforced ownership. The new architecture separates the fetch from the action, and the fetch was left unscoped.

Tests

Five tests added/extended across UpdateTest and ListTest:

  • user_cannot_read_another_users_notification — core IDOR: empty PATCH by another user returns 404
  • user_cannot_mark_another_users_notification_as_read — PATCH with isRead: true returns 404 and leaves read_at unchanged
  • admin_cannot_read_another_users_notification — admins are equally scoped; notifications are personal
  • listing_only_returns_own_notifications — confirms the listing endpoint is not affected
  • guest_cannot_update_notification — unauthenticated requests are rejected

The two IDOR tests fail against the unfixed code (returning 200) and pass after the fix.

Credit

Reported by Lakshmikanthan K (@l3tchupkt) via responsible disclosure. Thanks for the thorough and accurate report.

Changelog

Fixed: Authenticated users could read notification contents belonging to other users via the PATCH /api/notifications/{id} endpoint (IDOR). Reported by Lakshmikanthan K.

The Update endpoint for NotificationResource fetched notifications by ID
using an unscoped query, allowing any authenticated user to retrieve the
contents of any other user's notification by guessing its sequential ID.

The Index (listing) endpoint was correctly scoped via NotificationRepository,
but this scope was not applied to the Update path, which falls through to
AbstractDatabaseResource::find() — an unscoped Eloquent query.

Fix by overriding scope() in NotificationResource to unconditionally filter
all queries by the actor's user_id. This ensures any lookup — not just the
inbox listing — returns 404 for notifications belonging to other users.

The write side (marking a notification as read) was separately protected by
an ownership check in ReadNotificationHandler, so no data was ever modified
across ownership boundaries. The exposure was read-only.

Reported by Lakshmikanthan K (github.com/l3tchupkt) via responsible
disclosure. Thanks for the thorough and well-written report.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@imorland imorland requested a review from a team as a code owner March 14, 2026 21:12
@imorland imorland added this to the 2.0.0-beta.8 milestone Mar 14, 2026
@imorland imorland changed the title fix(notifications): scope notification queries to the authenticated user [2.x] fix(notifications): scope notification queries to the authenticated user Mar 14, 2026
@imorland imorland merged commit 63390b8 into 2.x Mar 14, 2026
30 of 58 checks passed
@imorland imorland deleted the im/fix-notification-idor branch March 14, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant