diff --git a/src/plainui/tests.py b/src/plainui/tests.py
index d59871afcb0da14589d1af593ba6130506f1034e..9692578a0f0eac8ca24200c86ed18bb15577c7ff 100644
--- a/src/plainui/tests.py
+++ b/src/plainui/tests.py
@@ -439,7 +439,7 @@ class ViewsTest(TestCase):
         r1_private_perm.save()
         r1_private_perm.set_public()
 
-        self.assertNeedsLogin(reverse('plainui:static_page', kwargs={'page_slug': sp.slug}))
+        self.assertNeedsLogin(reverse('plainui:static_page', kwargs={'page_slug': sp.slug}), check_conference_member=False)
         resp = self.client.get(reverse('plainui:static_page', kwargs={'page_slug': sp.slug}))
         self.assertEqual(resp.context_data['page_slug'], sp.slug)
         self.assertEqual(resp.context_data['conf'], self.conf)
@@ -536,7 +536,7 @@ class ViewsTest(TestCase):
         r2_de.save()
         r2_de.set_public()
 
-        self.assertNeedsLogin(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}), check_user=True)
+        self.assertNeedsLogin(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}), check_user=True, check_conference_member=False)
         resp = self.client.get(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}))
         self.assertEqual(resp.context_data['conf'], self.conf)
         self.assertEqual(resp.context_data['page'], sp)
@@ -588,7 +588,24 @@ class ViewsTest(TestCase):
         self.assertEqual(resp.context_data['form'].fields['title'].disabled, True)
         self.assertEqual(resp.context_data['form'].fields['body'].disabled, True)
 
+        # non-ticket user tries to edit a conference page
+        sp.privacy = StaticPage.Privacy.CONFERENCE
+        sp.save()
+        self.client.force_login(self.user_no_ticket)
+        resp = self.client.get(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}))
+        self.assertRedirects(resp, reverse('plainui:redeem_token'))
+        self.assertSetsMessage(resp, 'You do not have the required permissions to edit this page.', level=messages.ERROR)
+
+        # non-staff user tries to access an admin-accessible-only page
+        sp.privacy = StaticPage.Privacy.PERM
+        sp.save()
+        self.client.force_login(self.user)
+        resp = self.client.get(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}))
+        self.assertRedirects(resp, reverse('plainui:static_page', kwargs={'page_slug': sp.slug}))
+        self.assertSetsMessage(resp, 'You do not have the required permissions to edit this page.', level=messages.ERROR)
+
         # readonly via configured namespace
+        sp.privacy = StaticPage.Privacy.NONE
         sp.protection = StaticPage.Protection.NONE
         sp.save()
         ns = StaticPageNamespace('TEST')
@@ -645,8 +662,9 @@ class ViewsTest(TestCase):
             with override_locale('en'):
                 resp = self.client.get(reverse('plainui:static_page_edit', kwargs={'page_slug': 'test-doesnotexist'}))
                 self.assertRedirects(resp, reverse('plainui:static_page', kwargs={'page_slug': 'test-doesnotexist'}))
+                self.assertSetsMessage(resp, 'You do not have the required permissions to create this page.', level=messages.ERROR)
 
-        # nonexistend page, NOT in namespace -> show form with default values
+        # nonexistent page, NOT in namespace -> show form with default values
         resp = self.client.get(reverse('plainui:static_page_edit', kwargs={'page_slug': 'test-doesnotexist'}))
         self.assertEqual(resp.context_data['conf'], self.conf)
         self.assertEqual(resp.context_data['page_slug'], 'test-doesnotexist')
@@ -674,7 +692,7 @@ class ViewsTest(TestCase):
         r1_de.save()
         r1_de.set_public()
 
-        self.assertNeedsLogin(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}), post=True, check_user=True)
+        self.assertNeedsLogin(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}), post=True, check_user=True, check_conference_member=False)
 
         # invalid input body
         resp = self.client.post(reverse('plainui:static_page_edit', kwargs={'page_slug': sp.slug}), {'title': 'New Title', 'body': ''})
diff --git a/src/plainui/views.py b/src/plainui/views.py
index e82a2ac4c1d2554f875602f3428ed672ba526e2e..a9092e63a4ee272a2b1233be7ce806d2862a8108 100644
--- a/src/plainui/views.py
+++ b/src/plainui/views.py
@@ -447,6 +447,7 @@ class SearchView(ConferenceRequiredMixin, TemplateView):
 
 class StaticPageView(ConferenceRequiredMixin, TemplateView):
     template_name = 'plainui/static_page.html'
+    require_conference_member = False
 
     def get(self, request, page_slug, **kwargs):
         self.static_page = StaticPage.objects.conference_accessible(conference=self.conf, language=get_language()).filter(slug=page_slug).first()
@@ -516,6 +517,7 @@ class StaticPageView(ConferenceRequiredMixin, TemplateView):
 class StaticPageEditView(ConferenceRequiredMixin, TemplateView):
     template_name = 'plainui/static_page_edit.html'
     require_user = True
+    require_conference_member = False
 
     def get(self, request, *args, page_slug, **kwargs):
         # TODO tgr diff-view
@@ -532,14 +534,18 @@ class StaticPageEditView(ConferenceRequiredMixin, TemplateView):
                 static_page.language = None
 
         if not static_page:
+            # the page does not exist and the user does not have the permission to create it
+            messages.error(request, gettext("You do not have the required permissions to create this page."))
             return redirect(reverse('plainui:static_page', kwargs={'page_slug': page_slug}))
 
         if static_page.privacy == StaticPage.Privacy.CONFERENCE and not self.has_ticket(request):
-            return redirect(reverse('plainui:static_page', kwargs={'page_slug': page_slug}))
+            messages.error(request, gettext("You do not have the required permissions to edit this page."))
+            # TODO: after redeem, redirect to edit view for page_slug
+            return redirect(reverse('plainui:redeem_token'))
 
-        if static_page.privacy == StaticPage.Privacy.PERM:
-            if not self.request.user.has_conference_staffpermission(self.conf, 'static_pages'):
-                return redirect(reverse('plainui:static_page', kwargs={'page_slug': page_slug}))
+        if static_page.privacy == StaticPage.Privacy.PERM and not self.request.user.has_conference_staffpermission(self.conf, 'static_pages'):
+            messages.error(request, gettext("You do not have the required permissions to edit this page."))
+            return redirect(reverse('plainui:static_page', kwargs={'page_slug': page_slug}))
 
         revision = request.GET.get('rev')
         if revision:
@@ -1302,11 +1308,18 @@ class PersonalMessageDeleteView(ConferenceRequiredMixin, View):
 class IndexView(ConferenceRequiredMixin, TemplateView):
     template_name = 'plainui/index.html'
 
-    def _fetch_page(self, slug, default_title: str = 'Page Missing', default_body: str = 'Please configure the wiki page "{slug}" (or change slug).'):
+    def _fetch_page(self, slug, default_title: str = None, default_body: str = None):
         try:
             static_page = StaticPage.objects.conference_accessible(conference=self.conf, language=get_language()).get(slug=slug)
         except StaticPage.DoesNotExist:
-            static_page = StaticPage(conference=self.conf, title=default_title, body_html=default_body.format(slug=slug))
+            if not default_title:
+                default_title = 'Page Missing'
+
+            if not default_body:
+                url = reverse("plainui:static_page_edit", kwargs={"page_slug": slug})
+                default_body = 'Please configure the wiki page "{slug}" (or change slug). <a href="{url}">(edit)</a>'
+
+            static_page = StaticPage(conference=self.conf, title=default_title, body_html=default_body.format(slug=slug, url=url))
         return static_page
 
     def get_context_data(self, **kwargs):