diff --git a/arkindex/documents/serializers/elements.py b/arkindex/documents/serializers/elements.py
index e44ffc75b468d6754cf6f84c10f79145df347879..e4c08bae036d124322bc4556fc727ff68d16123d 100644
--- a/arkindex/documents/serializers/elements.py
+++ b/arkindex/documents/serializers/elements.py
@@ -83,6 +83,16 @@ class CorpusSerializer(serializers.ModelSerializer):
             count = corpus.corpus_right.count()
         return count
 
+    def validate_public(self, public):
+        """
+        Only an admin can toggle a corpus public property
+        Normal users may create private corpus only
+        """
+        toggled = self.instance and self.instance.public != public
+        if (toggled or public) and not self.context['request'].user.is_admin:
+            raise ValidationError(['Only admin users are allowed to edit the public attribute on a corpus.'])
+        return public
+
     def create(self, validated_data):
         corpus = Corpus.objects.create(**validated_data)
         corpus.corpus_right.create(
diff --git a/arkindex/documents/tests/test_corpus.py b/arkindex/documents/tests/test_corpus.py
index 9c1f03a7669f07c6f1b2f3ae59c78a507d0b0c3e..f33d2c65cc239ce97bf32634916dc268d386a2a8 100644
--- a/arkindex/documents/tests/test_corpus.py
+++ b/arkindex/documents/tests/test_corpus.py
@@ -262,7 +262,46 @@ class TestCorpus(FixtureAPITestCase):
             [str(vol1.id), str(vol2.id)],
         )
 
+    def test_create_requires_login(self):
+        response = self.client.post(reverse('api:corpus'), {
+            'name': 'New Corpus',
+            'description': 'Some description',
+            'public': False,
+        })
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+    def test_create_public_admin(self):
+        """
+        Administrators can create a public corpus
+        """
+        self.client.force_login(self.superuser)
+        response = self.client.post(reverse('api:corpus'), {
+            'name': 'New Corpus',
+            'description': 'Some description',
+            'public': True,
+        })
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+        self.assertTrue(Corpus.objects.get(name='New Corpus').public)
+
+    def test_create_public_normal_user(self):
+        """
+        Normal users cannot create a public corpus
+        """
+        self.client.force_login(self.user)
+        response = self.client.post(reverse('api:corpus'), {
+            'name': 'New Corpus',
+            'description': 'Some description',
+            'public': True,
+        })
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'public': ['Only admin users are allowed to edit the public attribute on a corpus.']
+        })
+
     def test_create(self):
+        """
+        Any user is able to create a corpus defining its name and description
+        """
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:corpus'), {
             'name': 'New Corpus',
@@ -290,14 +329,6 @@ class TestCorpus(FixtureAPITestCase):
             } for values in DEFAULT_CORPUS_TYPES]
         )
 
-    def test_create_requires_login(self):
-        response = self.client.post(reverse('api:corpus'), {
-            'name': 'New Corpus',
-            'description': 'Some description',
-            'public': False,
-        })
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
     def test_retrieve_public(self):
         response = self.client.get(reverse('api:corpus-retrieve', kwargs={'pk': self.corpus_public.id}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -377,6 +408,51 @@ class TestCorpus(FixtureAPITestCase):
         self.assertEqual(self.corpus_private.name, 'new name')
         self.assertEqual(self.corpus_private.description, 'new description')
 
+    def test_update_private_to_public_normal_user(self):
+        """
+        A normal user should not be able to make a private corpus public
+        """
+        self.client.force_login(self.user)
+        response = self.client.patch(reverse('api:corpus-retrieve', kwargs={'pk': self.corpus_private.id}), {
+            'public': True
+        })
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'public': ['Only admin users are allowed to edit the public attribute on a corpus.']
+        })
+
+    def test_update_public_to_private_normal_user(self):
+        """
+        A normal user should not be able to make a public corpus private
+        even if he has a write access to this corpus
+        """
+        self.client.force_login(self.user)
+        self.assertTrue(self.corpus_public.corpus_right.get(user=self.user).can_write)
+        response = self.client.patch(reverse('api:corpus-retrieve', kwargs={'pk': self.corpus_public.id}), {
+            'public': False
+        })
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'public': ['Only admin users are allowed to edit the public attribute on a corpus.']
+        })
+
+    def test_normal_user_update_public_corpus(self):
+        """
+        An user with no write right should not be able to edit a public corpus
+        """
+        self.client.force_login(self.user)
+        right = self.corpus_public.corpus_right.get(user=self.user)
+        right.can_write = False
+        right.can_admin = False
+        right.save()
+        response = self.client.patch(reverse('api:corpus-retrieve', kwargs={'pk': self.corpus_public.id}), {
+            'name': 'Gloubiboulga',
+            'description': 'Bla bla bla',
+            'public': False
+        })
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        self.assertDictEqual(response.json(), {'detail': 'You do not have write access to this corpus.'})
+
     def test_update_requires_login(self):
         response = self.client.patch(reverse('api:corpus-retrieve', kwargs={'pk': self.corpus_private.id}), {
             'name': 'new name',