From accd36da52a02ac9cabe5b045e3626108989832e Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Wed, 17 Jun 2026 06:37:03 +0800 Subject: [PATCH] fix(security): guest portal must key full object names (crm_lead/crm_case) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Web-to-Lead / Web-to-Case guest profile granted INSERT on `lead`/`case`, but the anonymous public-form permission path checks the FULL object name (`crm_lead`/`crm_case`) — so the short-name grant never matched and the anonymous insert was denied ("not permitted for roles []"). Use full names. (The short-name keys other profiles use resolve only on the authenticated path; the explicit-permission-set path used for anonymous submissions does not namespace short→full — tracked upstream in objectstack/framework#1989.) Verified end-to-end: anonymous POST /api/v1/forms/contact-us/submit creates a crm_lead; /forms/support creates a crm_case; guests still get 401 on reads. NOTE: requires the framework fix objectstack/framework#1989 (public-form resolution from flattened view metadata) to be released — until HotCRM bumps to that release, the form still resolves as FORM_NOT_FOUND on published @9.8.0. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/profiles/guest-portal.profile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/profiles/guest-portal.profile.ts b/src/profiles/guest-portal.profile.ts index a7e0bd7a..e05088c7 100644 --- a/src/profiles/guest-portal.profile.ts +++ b/src/profiles/guest-portal.profile.ts @@ -21,7 +21,7 @@ export const GuestPortalProfile = { 'Anonymous visitors submitting public Web-to-Lead / Web-to-Case forms. ' + 'INSERT-only on lead and case; no read/edit/delete on any object.', objects: { - lead: { + crm_lead: { allowCreate: true, allowRead: false, allowEdit: false, @@ -29,7 +29,7 @@ export const GuestPortalProfile = { viewAllRecords: false, modifyAllRecords: false, }, - case: { + crm_case: { allowCreate: true, allowRead: false, allowEdit: false,