Half the scoped apps I review have Caller Access set to All Application Scopes because the developer was tired of fighting the cross-scope privilege prompt. That setting voids the entire reason for scoping in the first place.
The model nobody bothers to read
A scoped application owns its tables, its scripts, and a privilege boundary. When code in scope A calls a Script Include in scope B, scope B must explicitly grant the operation. That grant lives in sys_scope_privilege and is supposed to be reviewed.
The three privilege types you must distinguish
- Read API — calling a function, executing a Script Include
- Write Field / Read Field — accessing fields on a foreign table
- Create / Update / Delete record — full CRUD on a foreign table
A grant of “Execute API” is not the same as “Update record.” Stop treating the prompt as a single accept-all decision.
The right pattern: explicit Script Include APIs
Expose a thin, deliberate API from scope B. Never let scope A reach into scope B’s internals.
// In scope B: x_acme_billing.PublicAPI
var PublicAPI = Class.create();
PublicAPI.prototype = {
getInvoiceTotal: function(invoiceId) {
var gr = new GlideRecord('x_acme_billing_invoice');
if (!gr.get(invoiceId)) return null;
return gr.getValue('total');
},
type: 'PublicAPI'
};
Set Accessible from: All application scopes only on PublicAPI. Internal helpers stay private.
Audit your sys_scope_privilege table
Every quarter, run:
var gr = new GlideRecord('sys_scope_privilege');
gr.addQuery('status', 'allowed');
gr.addQuery('operation', 'write_record');
gr.query();
Every row is a write grant from one scope to another. Confirm each is intentional and matches an architecture decision record.
Stop using global as a shortcut
Putting a Script Include in global to dodge cross-scope rules is a debt with compound interest. Upgrade-time conflicts and security findings will track you forever. Build the scoped API and grant it.
What to do this week
Pick your most-installed scoped app. Audit its sys_scope_privilege records. Anywhere you find a write_record grant that is not paired with a documented use case, revoke it and let the breakage tell you what was depending on it.