The general record endpoints (PATCH /records/:id, DELETE /records/:id, PUT /records/:id/permissions, etc.) currently accept requests targeting any record type, including system-defined types. For some of those types, allowing arbitrary edits via the API produces incorrect server behavior or a privilege escalation vector.
_attachment@1 — immutable fields
_attachment@1 records are written once by the server at upload time. Their fields describe physical facts about the stored blob:
fileId — content-addressed blob identifier. Changing it severs the link between the metadata record and the stored bytes; GET and DELETE both use this field to locate the blob.
size — used as the Content-Length response header. An incorrect value causes some HTTP clients to truncate the response or hang waiting for bytes that never arrive.
mimeType — used as the Content-Type response header. An incorrect value causes clients to misinterpret the content; setting it to text/html on an uploaded binary file is a XSS vector if X-Content-Type-Options: nosniff is not set.
filename is the only field with a legitimate reason to change (e.g. a user renaming their upload). fileId, size, and mimeType should be treated as immutable after creation.
Fix: Reject any PATCH /records/:id request that attempts to change fileId, size, or mimeType on an _attachment@1 record.
_grant@1 — privilege escalation
_grant@1 records are the permission system. Each record carries a typeId (which record type the grant covers) and actions (the set of operations permitted). If a non-owner entity holds a grant that includes update-own on _grant@1, they can use PATCH /records/:id to rewrite their own grant record — changing actions to include read-any, update-any, delete-any, etc. — and escalate to arbitrary privileges.
Fix: Reject PATCH /records/:id and DELETE /records/:id requests targeting _grant@1 records from any non-owner entity. Grant management should be owner-only at the API level.
The general record endpoints (
PATCH /records/:id,DELETE /records/:id,PUT /records/:id/permissions, etc.) currently accept requests targeting any record type, including system-defined types. For some of those types, allowing arbitrary edits via the API produces incorrect server behavior or a privilege escalation vector._attachment@1— immutable fields_attachment@1records are written once by the server at upload time. Their fields describe physical facts about the stored blob:fileId— content-addressed blob identifier. Changing it severs the link between the metadata record and the stored bytes; GET and DELETE both use this field to locate the blob.size— used as theContent-Lengthresponse header. An incorrect value causes some HTTP clients to truncate the response or hang waiting for bytes that never arrive.mimeType— used as theContent-Typeresponse header. An incorrect value causes clients to misinterpret the content; setting it totext/htmlon an uploaded binary file is a XSS vector ifX-Content-Type-Options: nosniffis not set.filenameis the only field with a legitimate reason to change (e.g. a user renaming their upload).fileId,size, andmimeTypeshould be treated as immutable after creation.Fix: Reject any
PATCH /records/:idrequest that attempts to changefileId,size, ormimeTypeon an_attachment@1record._grant@1— privilege escalation_grant@1records are the permission system. Each record carries atypeId(which record type the grant covers) andactions(the set of operations permitted). If a non-owner entity holds a grant that includesupdate-ownon_grant@1, they can usePATCH /records/:idto rewrite their own grant record — changingactionsto includeread-any,update-any,delete-any, etc. — and escalate to arbitrary privileges.Fix: Reject
PATCH /records/:idandDELETE /records/:idrequests targeting_grant@1records from any non-owner entity. Grant management should be owner-only at the API level.