diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py
index 2a0889262e349d0479f4d55f03e8941b5f274bb7..4ebbaee0bc302de092b4f0676eb107254602a547 100644
--- a/aleksis/core/rules.py
+++ b/aleksis/core/rules.py
@@ -8,6 +8,7 @@ from .util.predicates import (
     is_current_person,
     has_object_perm,
     is_group_owner,
+    is_notification_recipient,
 )
 
 
@@ -104,6 +105,10 @@ add_perm("core.manage_school", manage_school_predicate)
 manage_data_predicate = has_person & has_global_perm("core.manage_data")
 add_perm("core.manage_data", manage_data_predicate)
 
+# Mark notification as read
+mark_notification_as_read_predicate = has_person & is_notification_recipient
+add_perm("core.mark_notification_as_read", mark_notification_as_read_predicate)
+
 # View announcements
 view_announcements_predicate = has_person & (
     has_global_perm("core.view_announcement") | has_any_object("core.view_announcement", Announcement)
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
index 396fdbf3a643e96c75394581a67aa98874a13f64..bdfa1c0cdede47436cb3b967be819cc2db0cbd4e 100644
--- a/aleksis/core/util/predicates.py
+++ b/aleksis/core/util/predicates.py
@@ -90,3 +90,9 @@ def is_group_owner(user: User, group: Group) -> bool:
 
     return group.owners.filter(owners=user.person).exists()
 
+
+@predicate
+def is_notification_recipient(user: User, obj: Model) -> bool:
+    """ Predicate which checks whether the recipient of the notification a user wants to mark read is this user """
+
+    return user == obj.recipient.user
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index f005233c4808d58f747461d32288c923aaa342ba..e89caf6b93b2931fc0c4de3cdd261cdeaaf52610 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -301,18 +301,20 @@ def system_status(request: HttpRequest) -> HttpResponse:
     return render(request, "core/system_status.html", context)
 
 
+def get_notification_by_pk(request: HttpRequest, pk: int):
+    return get_object_or_404(Notification, pk=pk)
+
+
+@permission_required("core.mark_notification_as_read", fn=get_notification_by_pk)
 def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse:
     """ Mark a notification read """
 
     context = {}
 
-    notification = get_object_or_404(Notification, pk=id_)
+    notification = get_notification_by_pk(request, id_)
 
-    if notification.recipient.user == request.user:
-        notification.read = True
-        notification.save()
-    else:
-        raise PermissionDenied(_("You are not allowed to mark notifications from other users as read!"))
+    notification.read = True
+    notification.save()
 
     # Redirect to dashboard as this is only used from there if JavaScript is unavailable
     return redirect("index")