diff --git a/frontend/cypress/e2e/permissions.spec.ts b/frontend/cypress/e2e/permissions.spec.ts
new file mode 100644
index 000000000..52c3ed117
--- /dev/null
+++ b/frontend/cypress/e2e/permissions.spec.ts
@@ -0,0 +1,115 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import type { NotePermissions } from '@hedgedoc/commons'
+
+const mockPermissionChangeApiRoutes = (permission: NotePermissions) => {
+  cy.intercept('PUT', 'api/private/notes/mock-note/metadata/permissions/groups/_EVERYONE', {
+    statusCode: 200,
+    body: permission
+  })
+  cy.intercept('DELETE', 'api/private/notes/mock-note/metadata/permissions/groups/_EVERYONE', {
+    statusCode: 200,
+    body: permission
+  })
+  cy.intercept('PUT', 'api/private/notes/mock-note/metadata/permissions/groups/_LOGGED_IN', {
+    statusCode: 200,
+    body: permission
+  })
+  cy.intercept('DELETE', 'api/private/notes/mock-note/metadata/permissions/groups/_LOGGED_IN', {
+    statusCode: 200,
+    body: permission
+  })
+}
+
+describe('The permission settings modal', () => {
+  beforeEach(() => {
+    cy.visitTestNote()
+    cy.getByCypressId('sidebar-permission-btn').click()
+  })
+
+  it('can be displayed', () => {
+    cy.getByCypressId('permission-modal').should('be.visible')
+    cy.getByCypressId('permission-owner-name').contains('Mock User')
+    cy.getByCypressId('permission-setting-deny_LOGGED_IN').should('have.class', 'btn-secondary')
+    cy.getByCypressId('permission-setting-deny_EVERYONE').should('have.class', 'btn-secondary')
+  })
+
+  it('shows alert icon on invalid settings in special groups', () => {
+    cy.getByCypressId('permission-setting-deny_LOGGED_IN').should('have.class', 'btn-secondary')
+    mockPermissionChangeApiRoutes({
+      owner: 'mock',
+      sharedToUsers: [],
+      sharedToGroups: [
+        {
+          groupName: '_EVERYONE',
+          canEdit: false
+        }
+      ]
+    })
+    cy.getByCypressId('permission-setting-read_EVERYONE').click()
+    cy.get('svg.text-warning.me-2').should('be.visible')
+    mockPermissionChangeApiRoutes({
+      owner: 'mock',
+      sharedToUsers: [],
+      sharedToGroups: [
+        {
+          groupName: '_EVERYONE',
+          canEdit: true
+        }
+      ]
+    })
+    cy.getByCypressId('permission-setting-write_EVERYONE').click()
+    cy.get('svg.text-warning.me-2').should('be.visible')
+    mockPermissionChangeApiRoutes({
+      owner: 'mock',
+      sharedToUsers: [],
+      sharedToGroups: [
+        {
+          groupName: '_EVERYONE',
+          canEdit: false
+        },
+        {
+          groupName: '_LOGGED_IN',
+          canEdit: false
+        }
+      ]
+    })
+    cy.getByCypressId('permission-setting-read_LOGGED_IN').click()
+    cy.get('svg.text-warning.me-2').should('not.exist')
+    mockPermissionChangeApiRoutes({
+      owner: 'mock',
+      sharedToUsers: [],
+      sharedToGroups: [
+        {
+          groupName: '_EVERYONE',
+          canEdit: true
+        },
+        {
+          groupName: '_LOGGED_IN',
+          canEdit: false
+        }
+      ]
+    })
+    cy.getByCypressId('permission-setting-write_EVERYONE').click()
+    cy.get('svg.text-warning.me-2').should('be.visible')
+    mockPermissionChangeApiRoutes({
+      owner: 'mock',
+      sharedToUsers: [],
+      sharedToGroups: [
+        {
+          groupName: '_EVERYONE',
+          canEdit: true
+        },
+        {
+          groupName: '_LOGGED_IN',
+          canEdit: true
+        }
+      ]
+    })
+    cy.getByCypressId('permission-setting-write_LOGGED_IN').click()
+    cy.get('svg.text-warning.me-2').should('not.exist')
+  })
+})
diff --git a/frontend/cypress/support/visit-test-editor.ts b/frontend/cypress/support/visit-test-editor.ts
index b844f9e55..952470528 100644
--- a/frontend/cypress/support/visit-test-editor.ts
+++ b/frontend/cypress/support/visit-test-editor.ts
@@ -6,35 +6,37 @@
 import type { Note } from '../../src/api/notes/types'
 
 export const testNoteId = 'test'
+const mockMetadata = {
+  id: testNoteId,
+  aliases: [
+    {
+      name: 'mock-note',
+      primaryAlias: true,
+      noteId: testNoteId
+    }
+  ],
+  primaryAddress: 'mock-note',
+  title: 'Mock Note',
+  description: 'Mocked note for testing',
+  tags: ['test', 'mock', 'cypress'],
+  updatedAt: '2021-04-24T09:27:51.000Z',
+  updateUsername: null,
+  viewCount: 0,
+  version: 2,
+  createdAt: '2021-04-24T09:27:51.000Z',
+  editedBy: [],
+  permissions: {
+    owner: 'mock',
+    sharedToUsers: [],
+    sharedToGroups: []
+  }
+}
 
 beforeEach(() => {
   cy.intercept(`api/private/notes/${testNoteId}`, {
     content: '',
-    metadata: {
-      id: testNoteId,
-      aliases: [
-        {
-          name: 'mock-note',
-          primaryAlias: true,
-          noteId: testNoteId
-        }
-      ],
-      primaryAddress: 'mock-note',
-      title: 'Mock Note',
-      description: 'Mocked note for testing',
-      tags: ['test', 'mock', 'cypress'],
-      updatedAt: '2021-04-24T09:27:51.000Z',
-      updateUsername: null,
-      viewCount: 0,
-      version: 2,
-      createdAt: '2021-04-24T09:27:51.000Z',
-      editedBy: [],
-      permissions: {
-        owner: 'mock',
-        sharedToUsers: [],
-        sharedToGroups: []
-      }
-    },
+    metadata: mockMetadata,
     editedByAtPosition: []
   } as Note)
+  cy.intercept(`api/private/notes/${testNoteId}/metadata`, mockMetadata)
 })
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx
index 06fb19c08..344faf513 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx
@@ -16,6 +16,7 @@ import { ToggleButtonGroup } from 'react-bootstrap'
 import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons'
 import { useTranslation } from 'react-i18next'
 import { PermissionInconsistentAlert } from './permission-inconsistent-alert'
+import { cypressId } from '../../../../../../utils/cypress-attribute'
 
 export interface PermissionEntrySpecialGroupProps {
   level: AccessLevel
@@ -101,6 +102,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
             onClick={onSetEntryDenied}
             disabled={disabled}
             className={'p-1'}
+            {...cypressId(`permission-setting-deny${type}`)}
           />
           <IconButton
             icon={IconEye}
@@ -109,6 +111,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
             onClick={onSetEntryReadOnly}
             disabled={disabled}
             className={'p-1'}
+            {...cypressId(`permission-setting-read${type}`)}
           />
           <IconButton
             icon={IconPencil}
@@ -117,6 +120,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
             onClick={onSetEntryWriteable}
             disabled={disabled}
             className={'p-1'}
+            {...cypressId(`permission-setting-write${type}`)}
           />
         </ToggleButtonGroup>
       </div>
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx
index da59e74e5..c747b4691 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx
@@ -11,6 +11,7 @@ import { PermissionSectionSpecialGroups } from './permission-section-special-gro
 import { PermissionSectionUsers } from './permission-section-users'
 import React from 'react'
 import { Modal } from 'react-bootstrap'
+import { cypressId } from '../../../../../../utils/cypress-attribute'
 
 /**
  * Modal for viewing and managing the permissions of the note.
@@ -21,7 +22,12 @@ import { Modal } from 'react-bootstrap'
 export const PermissionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
   const isOwner = useIsOwner()
   return (
-    <CommonModal show={show} onHide={onHide} showCloseButton={true} titleI18nKey={'editor.modal.permissions.title'}>
+    <CommonModal
+      show={show}
+      onHide={onHide}
+      showCloseButton={true}
+      titleI18nKey={'editor.modal.permissions.title'}
+      {...cypressId('permission-modal')}>
       <Modal.Body>
         <PermissionSectionOwner disabled={!isOwner} />
         <PermissionSectionUsers disabled={!isOwner} />
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx
index 0da3a8cc3..6d49466e4 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx
@@ -12,6 +12,7 @@ import { PermissionOwnerChange } from './permission-owner-change'
 import { PermissionOwnerInfo } from './permission-owner-info'
 import React, { Fragment, useCallback, useState } from 'react'
 import { Trans } from 'react-i18next'
+import { cypressId } from '../../../../../../utils/cypress-attribute'
 
 /**
  * Section in the permissions modal for managing the owner of a note.
@@ -50,7 +51,9 @@ export const PermissionSectionOwner: React.FC<PermissionDisabledProps> = ({ disa
         <Trans i18nKey={'editor.modal.permissions.owner'} />
       </h5>
       <ul className={'list-group'}>
-        <li className={'list-group-item d-flex flex-row align-items-center justify-content-between'}>
+        <li
+          className={'list-group-item d-flex flex-row align-items-center justify-content-between'}
+          {...cypressId('permission-owner-name')}>
           {changeOwner ? (
             <PermissionOwnerChange onConfirmOwnerChange={onOwnerChange} />
           ) : (
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx
index 6f6e89cbf..dd35f4d95 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx
@@ -10,6 +10,7 @@ import { PermissionModal } from './permissions-modal/permission-modal'
 import React, { Fragment } from 'react'
 import { Lock as IconLock } from 'react-bootstrap-icons'
 import { Trans, useTranslation } from 'react-i18next'
+import { cypressId } from '../../../../../utils/cypress-attribute'
 
 /**
  * Renders a button to open the permission modal for the sidebar.
@@ -23,7 +24,12 @@ export const PermissionsSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ c
 
   return (
     <Fragment>
-      <SidebarButton hide={hide} className={className} icon={IconLock} onClick={showModal}>
+      <SidebarButton
+        hide={hide}
+        className={className}
+        icon={IconLock}
+        onClick={showModal}
+        {...cypressId('sidebar-permission-btn')}>
         <Trans i18nKey={'editor.modal.permissions.title'} />
       </SidebarButton>
       <PermissionModal show={modalVisibility} onHide={closeModal} />
diff --git a/frontend/src/pages/api/private/users/mock.ts b/frontend/src/pages/api/private/users/mock.ts
new file mode 100644
index 000000000..2a790f40e
--- /dev/null
+++ b/frontend/src/pages/api/private/users/mock.ts
@@ -0,0 +1,18 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import type { UserInfo } from '../../../../api/users/types'
+import { HttpMethod, respondToMatchingRequest } from '../../../../handler-utils/respond-to-matching-request'
+import type { NextApiRequest, NextApiResponse } from 'next'
+
+const handler = (req: NextApiRequest, res: NextApiResponse): void => {
+  respondToMatchingRequest<UserInfo>(HttpMethod.GET, req, res, {
+    username: 'mock',
+    displayName: 'Mock User',
+    photoUrl: ''
+  })
+}
+
+export default handler