diff --git a/beat/web/common/serializers.py b/beat/web/common/serializers.py
index cd52ad970de0a80311e674cee47c29ffbc2b8a55..e451ce0d32fe933e0d1c77dbbeab27ae52192da9 100644
--- a/beat/web/common/serializers.py
+++ b/beat/web/common/serializers.py
@@ -33,10 +33,12 @@ from django.contrib.auth.models import User
 from django.utils import six
 
 from rest_framework import serializers
+from rest_framework import exceptions as drf_exceptions
 
 from ..team.models import Team
 from ..common.utils import ensure_html
 from ..common.utils import annotate_full_name
+from ..common.utils import validate_restructuredtext
 
 from .models import Shareable, Versionable, Contribution
 from .exceptions import ContributionCreationError
@@ -298,24 +300,55 @@ class ContributionSerializer(VersionableSerializer):
 # ----------------------------------------------------------
 
 
-class ContributionCreationSerializer(serializers.ModelSerializer):
+class ContributionModSerializer(serializers.ModelSerializer):
     declaration = JSONSerializerField(required=False)
     description = serializers.CharField(required=False, allow_blank=True)
+
+    class Meta:
+        fields = ["short_description", "description", "declaration"]
+        beat_core_class = None
+
+    def validate_description(self, description):
+        if description.find("\\") >= 0:  # was escaped, unescape
+            description = description.decode("string_escape")
+        validate_restructuredtext(description)
+        return description
+
+    def validate_declaration(self, declaration):
+        decl = copy.deepcopy(declaration)
+        obj = self.Meta.beat_core_class(prefix=settings.PREFIX, data=decl)
+        if not obj.valid:
+            raise drf_exceptions.ValidationError(obj.errors)
+        return declaration
+
+    def update(self, instance, validated_data):
+        declaration = validated_data.get("declaration")
+
+        if declaration is not None and not instance.modifiable():
+            raise drf_exceptions.PermissionDenied(
+                "The {} isn't modifiable anymore (either shared with someone else, or needed by an attestation)".format(
+                    self.Meta.model.__name__.lower()
+                )
+            )
+
+        return super().update(instance, validated_data)
+
+
+# ----------------------------------------------------------
+
+
+class ContributionCreationSerializer(ContributionModSerializer):
     fork_of = serializers.JSONField(required=False)
     previous_version = serializers.CharField(required=False)
     version = serializers.IntegerField(min_value=1)
 
-    class Meta:
-        fields = [
+    class Meta(ContributionModSerializer.Meta):
+        fields = ContributionModSerializer.Meta.fields + [
             "name",
-            "short_description",
-            "description",
-            "declaration",
             "previous_version",
             "fork_of",
             "version",
         ]
-        beat_core_class = None
 
     def validate_fork_of(self, fork_of):
         if "previous_version" in self.initial_data:
@@ -331,18 +364,6 @@ class ContributionCreationSerializer(serializers.ModelSerializer):
             )
         return previous_version
 
-    def validate_description(self, description):
-        if description.find("\\") >= 0:  # was escaped, unescape
-            description = description.decode("string_escape")
-        return description
-
-    def validate_declaration(self, declaration):
-        decl = copy.deepcopy(declaration)
-        obj = self.Meta.beat_core_class(prefix=settings.PREFIX, data=decl)
-        if not obj.valid:
-            raise serializers.ValidationError(obj.errors)
-        return declaration
-
     def validate_version(self, version):
         # If version is not one then it's necessarily a new version
         # forks start at one