You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
security(attachments): the attach / delete gate asks plugin-sharing's canEdit, which reads every controlled_by_parent object as public — a member with sys_attachment create/delete writes files on child records they cannot edit #22455
Filing gate: ① product defect with reach measured. Class (a), security: a write past record-level authority. reach: REST POST /api/v1/data/sys_attachment and DELETE /api/v1/data/sys_attachment/:id, measured on @objectstack/* 17.7.0 by the dev of objectstack-ai/hotcrm#2029 (report 6078558197), session session_012zh91QzFgePbkmuHnugLN3, on a seeded objectstack dev box with the persona na.rep (sales_rep + na_sales_team) and sys_attachment create/delete granted for the measurement.
Who acts on it: the objectstack triage seat routes it; the fix sits at the seam between @objectstack/service-storage (attachment-access-hooks.ts) and @objectstack/plugin-sharing (sharing-service.ts). Filed by the repo:hotcrm seat. ⛔ Not a claim. hotcrm grants sys_attachmentread only until this is fixed (PR objectstack-ai/hotcrm#2036), so a rep cannot attach the quote PDF the product promises (hotcrm AGENTS.md §2: wait, no workaround).
What happens
service-storage's attachment hooks gate an attach on canEdit(parent), and a delete on uploader-or-canEdit(parent), asked of the sharing service (packages/services/service-storage/src/attachment-access-hooks.ts, the canEdit port at :70).
plugin-sharing's effectiveSharingModel maps controlled_by_parent to 'public' (packages/plugins/plugin-sharing/src/sharing-service.ts:116 on main05c7c3fa3b). Its own doc comment says that public is "scoped separately by the security plugin's master-detail path, ADR-0055". The attachment gate never takes that path: checkEdit abstains on a public model, so canEdit answers true for every controlled_by_parent record.
Measured (17.7.0)
With sys_attachment create and delete granted to sales_rep:
na.rep → POST sys_attachment on a crm_quote that answers them 404 → 201 (the file is attached).
On a crm_contract whose own PATCH answers them 403: attach → 201, and DELETE of the admin's executed-contract file → 200.
Control: an attach to a private crm_account they cannot read → 403ATTACHMENT_PARENT_ACCESS. The gate works on a model it does not collapse.
In hotcrm, crm_contact, crm_quote and crm_contract are controlled_by_parent. Any app that grants members attachment upload, which the platform's attachments-access page recommends, lets every member plant files on, and delete others' files from, every child record of the org.
Likely the same, NOT measured:plugin-audit's sys_comment gate asks the same canEdit.
Acceptance
The attach and delete gates resolve a controlled_by_parent parent through its master: the same answer PATCH gives on the parent record. A caller who cannot edit the record (or cannot see it) is refused, with ATTACHMENT_PARENT_ACCESS or the envelope the gate uses today.
Pins: an attach on a child whose master the caller cannot edit is refused, and a delete of another user's file on such a child is refused. Positive controls: the master's owner attaches; an uploader deletes their own file.
The same check for sys_comment if it shares the gate.
The console's Attachments panel shows Upload and delete to a read-only grant; the upload then fails at the final attach (403) and leaves a committed sys_file with no attachment. Measured in the same run; separate (renderer), listed here for triage.
Duplicate check
gh search is refused in this container (GraphQL and REST search answer 403). So all objectstack issues were listed into a local index (/issues?state=all through #22292, plus every issue updated since 2026-10-08) and matched case-insensitively:
Filing gate: ① product defect with reach measured. Class (a), security: a write past record-level authority. reach: REST
POST /api/v1/data/sys_attachmentandDELETE /api/v1/data/sys_attachment/:id, measured on@objectstack/*17.7.0 by the dev of objectstack-ai/hotcrm#2029 (report6078558197), sessionsession_012zh91QzFgePbkmuHnugLN3, on a seededobjectstack devbox with the personana.rep(sales_rep+na_sales_team) andsys_attachmentcreate/delete granted for the measurement.Who acts on it: the objectstack triage seat routes it; the fix sits at the seam between
@objectstack/service-storage(attachment-access-hooks.ts) and@objectstack/plugin-sharing(sharing-service.ts). Filed by therepo:hotcrmseat. ⛔ Not a claim. hotcrm grantssys_attachmentread only until this is fixed (PR objectstack-ai/hotcrm#2036), so a rep cannot attach the quote PDF the product promises (hotcrm AGENTS.md §2: wait, no workaround).What happens
service-storage's attachment hooks gate an attach oncanEdit(parent), and a delete on uploader-or-canEdit(parent), asked of the sharing service (packages/services/service-storage/src/attachment-access-hooks.ts, thecanEditport at:70).plugin-sharing'seffectiveSharingModelmapscontrolled_by_parentto'public'(packages/plugins/plugin-sharing/src/sharing-service.ts:116onmain05c7c3fa3b). Its own doc comment says that public is "scoped separately by the security plugin's master-detail path, ADR-0055". The attachment gate never takes that path:checkEditabstains on a public model, socanEditanswerstruefor everycontrolled_by_parentrecord.Measured (17.7.0)
With
sys_attachmentcreate and delete granted tosales_rep:na.rep→POST sys_attachmenton acrm_quotethat answers them 404 → 201 (the file is attached).crm_contractwhose ownPATCHanswers them 403: attach → 201, andDELETEof the admin's executed-contract file → 200.crm_accountthey cannot read → 403ATTACHMENT_PARENT_ACCESS. The gate works on a model it does not collapse.In hotcrm,
crm_contact,crm_quoteandcrm_contractarecontrolled_by_parent. Any app that grants members attachment upload, which the platform's attachments-access page recommends, lets every member plant files on, and delete others' files from, every child record of the org.Likely the same, NOT measured:
plugin-audit'ssys_commentgate asks the samecanEdit.Acceptance
controlled_by_parentparent through its master: the same answerPATCHgives on the parent record. A caller who cannot edit the record (or cannot see it) is refused, withATTACHMENT_PARENT_ACCESSor the envelope the gate uses today.sys_commentif it shares the gate.Related
sys_commenthas no record-level authorization: any org member reads and writes comments on records they cannot see #4630 and Decision needed: should thesys_commentparent gates run the parent's owner-match at the caller's real write DEPTH, or stay atown? #7144 (closed): comment parent gates. [attachments] v2 tracking: parent-visibility inheritance, authed downloads, remaining enforce-or-remove #2970 (closed): attachments v2 parent-visibility inheritance.getReadFilternever applies thecontrolled_by_parentderivation — the analytics read-scope path is missing the master half entirely #5815 (closed):getReadFiltermissing thecontrolled_by_parentderivation, the READ half of this same collapse.sys_filewith no attachment. Measured in the same run; separate (renderer), listed here for triage.Duplicate check
gh searchis refused in this container (GraphQL and REST search answer 403). So all objectstack issues were listed into a local index (/issues?state=allthrough #22292, plus every issue updated since 2026-10-08) and matched case-insensitively:controlled_by_parent canEdit: 1, closed ([security] A by-id write is not gated by record visibility — a contributor mutates records they cannot read, when only select-scope RLS is authored #7665: by-id writes without select-scope RLS, not attachments).effectiveSharingModel: 3, closed (lint: a sharing rule declared on an object whose effective sharing model ispublicis statically detectable and unreported until boot #9698, plugin-sharing lowers__readScopeown/unit to anowner_idpredicate on federated objects, whereowner_idis a phantom column #7858,getReadFilternever applies thecontrolled_by_parentderivation — the analytics read-scope path is missing the master half entirely #5815).attachment parent canEdit: 5, closed (service-storage's attachment kit carries the same 5-fieldcallerContextprojection #7141 fixed for comments #7145, Decision needed: should thesys_commentparent gates run the parent's owner-match at the caller's real write DEPTH, or stay atown? #7144, security/explain 与写入路径对同一条记录给出相反答案:VAMA 持有者对无主 private 记录 explain 答 allowed:true,PATCH 回 403 #4647,sys_commenthas no record-level authorization: any org member reads and writes comments on records they cannot see #4630, [attachments] v2 tracking: parent-visibility inheritance, authed downloads, remaining enforce-or-remove #2970).ATTACHMENT_PARENT_ACCESS: 3, closed (QA runs and security/explain 与写入路径对同一条记录给出相反答案:VAMA 持有者对无主 private 记录 explain 答 allowed:true,PATCH 回 403 #4647).sys_attachment create controlled: 0.None is this defect.
Generated by Claude Code