The problem
When an app card calls an app function, HubSpot sets portalId and user on the server, so the function can trust who is calling. The record the card is displayed on gets no such guarantee. Its ID only reaches the function through parameters or propertiesToSend, in a request built by the browser, and HubSpot Support confirmed that the user’s access to that record isn’t checked.
So any function that returns data about the current record (an embedded report, a document, data from another system) has to rebuild record-level authorization itself. Otherwise a user can replay the call with another record’s ID and get data about a record they can’t open in HubSpot.
Why now
Legacy CRM cards received associatedObjectId in a request signed by HubSpot. They are deprecated on November 2, 2026, and app cards with app functions have no equivalent. Migrating removes a guarantee that apps relied on.
Proposal (any one of these would solve it)
- Add the record to the server-set context (for example
context.crm.objectIdandobjectTypeId), set only when the calling user can view that record. - Resolve
propertiesToSendwith the calling user’s permissions, and reject the call when they can’t view the record. - For
hubspot.fetch, append the record ID resolved by HubSpot to the signed query parameters, next touserIdandportalId.
Why it matters
HubSpot already knows which records each user can view. Enforcing that in the platform would make the common “card shows data about this record” pattern safe by default, instead of every app rebuilding it with the permitted-users API or its own ownership rules.
This was also filed as a feature request through HubSpot Support. If you build app cards that call a backend, an upvote helps.