VYPR
High severityNVD Advisory· Published Feb 8, 2024

Kinto Attachment's attachments can be replaced on read-only records

CVE-2024-1314

Description

Impact

The attachment file of an existing record can be replaced if the user has "read" permission on one of the parent (collection or bucket).

And if the "read" permission is given to "system.Everyone" on one of the parent, then the attachment can be replaced on a record using an anonymous request.

Note that if the parent has no explicit read permission, then the records attachments are safe.

Patches

  • Patch released in kinto-attachment 6.4.0
  • https://github.com/Kinto/kinto-attachment/commit/f4a31484f5925cbc02b59ebd37554538ab826ca1

Workarounds

None if the read permission has to remain granted.

Updating to 6.4.0 or applying the patch individually (if updating is not feasible) is strongly recommended.

References

  • https://bugzilla.mozilla.org/show_bug.cgi?id=1879034

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
kinto-attachmentPyPI
< 6.4.06.4.0

Patches

1
f4a31484f592

Merge pull request from GHSA-hvp4-vrv2-8wrq

https://github.com/Kinto/kinto-attachmentMathieu LeplatreFeb 8, 2024via ghsa
2 files changed · +50 3
  • src/kinto_attachment/utils.py+12 1 modified
    @@ -26,7 +26,11 @@
     
     class AttachmentRouteFactory(RouteFactory):
         def __init__(self, request):
    -        """Attachment is not a Kinto resource.
    +        """
    +        This class is the `context` object being passed to the
    +        :class:`kinto.core.authorization.AuthorizationPolicy`.
    +
    +        Attachment is not a Kinto resource.
     
             The required permission is:
             * ``write`` if the related record exists;
    @@ -43,12 +47,19 @@ def __init__(self, request):
                 existing = resource.get()
             except httpexceptions.HTTPNotFound:
                 existing = None
    +
             if existing:
    +            # Request write permission on the existing record.
                 self.permission_object_id = record_uri(request)
                 self.required_permission = "write"
             else:
    +            # Request create record permission on the parent collection.
                 self.permission_object_id = collection_uri(request)
                 self.required_permission = "create"
    +        # Set the current object in context, since it is used in the
    +        # authorization policy to distinguish operations on plural endpoints
    +        # from individual objects. See Kinto/kinto#918
    +        self.current_object = existing
     
     
     def sha256(content):
    
  • tests/test_views_attachment.py+38 2 modified
    @@ -283,21 +283,57 @@ def test_upload_refused_if_not_authenticated(self):
             self.headers.pop("Authorization")
             self.upload(status=401)
     
    +    def test_upload_replace_refused_if_not_authenticated(self):
    +        self.upload(status=201)
    +
    +        self.headers.pop("Authorization")
    +        self.upload(status=401)
    +
         def test_upload_refused_if_not_allowed(self):
             self.headers.update(get_user_headers("jean-louis"))
             self.upload(status=403)
     
         def test_upload_replace_refused_if_only_create_allowed(self):
    -        # Allow any authenticated to write in this bucket.
    +        # Allow any authenticated to write in this collection.
             perm = {"permissions": {"record:create": ["system.Authenticated"]}}
             self.app.patch_json("/buckets/fennec/collections/fonts", perm, headers=self.headers)
             self.upload(status=201)
     
             self.headers.update(get_user_headers("jean-louis"))
             self.upload(status=403)
     
    +    def test_upload_replace_refused_if_only_bucket_read_is_allowed(self):
    +        # Create a record with attachment.
    +        self.upload(status=201)
    +
    +        # Now allow anyone to read this bucket.
    +        perm = {"permissions": {"read": ["system.Everyone"]}}
    +        self.app.patch_json("/buckets/fennec", perm, headers=self.headers)
    +
    +        # And try to replace anonymously.
    +        self.headers.pop("Authorization")
    +        self.upload(status=401)
    +
    +    def test_upload_replace_refused_if_only_read_is_allowed(self):
    +        # Create a record with attachment.
    +        self.upload(status=201)
    +
    +        # Now allow anyone to read this collection.
    +        perm_change = [
    +            {"op": "add", "path": "/permissions", "value": {"read": ["system.Everyone"]}}
    +        ]
    +        self.app.patch_json(
    +            "/buckets/fennec/collections/fonts",
    +            perm_change,
    +            headers={**self.headers, "Content-Type": "application/json-patch+json"},
    +        )
    +
    +        # And try to replace anonymously.
    +        self.headers.pop("Authorization")
    +        self.upload(status=401)
    +
         def test_upload_create_accepted_if_create_allowed(self):
    -        # Allow any authenticated to write in this bucket.
    +        # Allow any authenticated to write in this collection.
             perm = {"permissions": {"record:create": ["system.Authenticated"]}}
             self.app.patch_json("/buckets/fennec/collections/fonts", perm, headers=self.headers)
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.