1. Table-Level, Field-Level & Row-Level ACLs
An Access Control (ACL) record, stored on
sys_security_acl, defines a permission for one operation —
create, read, write, or delete — on either a whole table or a single field.
A user needs a matching ACL to pass at every applicable level: a
table-level read ACL controls whether they can see the record at all; a
field-level ACL on top of that can still hide or lock one specific field even
when the record itself is visible.
If no ACL grants access for an operation on a table, that operation is denied by default for non-admin users. Access is something you explicitly grant via matching roles, not something you have to explicitly revoke — this is the opposite mental model from a system where everything's open until you lock it down.
2. Roles & Groups
A role (sys_user_role) is a named permission a
user can hold directly or inherit through group membership. Most ACLs specify
one or more "Requires role" entries — a user needs at least one of the listed
roles (unless the ACL's script says otherwise) for the ACL to grant access.
Table: incident
Operation: write
Requires role: itil (the standard ITSM agent role)
Roles typically nest — admin implicitly satisfies almost every
role check platform-wide, which is exactly why testing as admin hides access
problems that only show up once you impersonate a lower-privileged user.
3. ACL Scripts
When a role check alone isn't precise enough — "only the assigned agent or
their manager can write to this record" — an ACL can carry a script that sets
a boolean answer variable, evaluated in addition to (or instead
of) the role requirement.
answer = gs.hasRole('itil') &&
(current.assigned_to == gs.getUserID() ||
current.assignment_group.manager == gs.getUserID());
gs.hasRole('itil') checks the current user's roles server-side;
gs.getUserID() returns the logged-in user's sys_id for
comparison against reference fields on the record.
4. Debugging "Why Can't This User See This Record"
Two tools make ACL debugging tractable instead of guesswork: Impersonate User (User menu → Impersonate User) to actually experience the instance as that user, and the Security Debugger (System Security → Debug Security Rules) which logs every ACL evaluated for a request and whether it passed or failed — invaluable for the "which of these six ACLs on this table is actually blocking this user" situation.
5. Hands-on Exercise
Restrict write access to a custom field by role
Requirements:
- Add a custom field
u_internal_notesto the incident table. - Create a field-level write ACL on it requiring the
itil_adminrole (so regularitilagents can read but not write it). - Create a non-admin test user with only the
itilrole, and impersonate them to confirm the field is visible but read-only. - Turn on the Security Debugger, reload the incident form as that impersonated user, and locate the specific ACL entry in the debug log that denied write access.
If a field you expect to be locked down is still editable, check whether an admin-level ACL elsewhere is granting broader access that overrides your more specific one — the Security Debugger will show every ACL that was evaluated, in order, which makes this kind of conflict visible instead of mysterious.
6. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
Why can a record be visible on a list but still have one of its fields blank or uneditable?
Why can a record be visible on a list but still have one of its fields blank or uneditable?
Table-level and field-level ACLs are evaluated independently. A table-level read ACL controls whether the record shows up at all; a field-level ACL layered on top can still deny read or write access to one specific field even when the surrounding record is fully visible.
Q2
What does it mean that ACLs are "deny-by-default"?
What does it mean that ACLs are "deny-by-default"?
If no ACL exists granting a given operation on a table or field for a non-admin user, that operation is denied automatically — access has to be explicitly granted via a matching role, rather than being open by default and requiring explicit locking down.
Q3
Why does testing a feature only as the admin user risk missing real access bugs?
Why does testing a feature only as the admin user risk missing real access bugs?
The admin role implicitly satisfies nearly every role check on the platform, so admin sessions rarely trigger the ACL denials a regular agent or end user would hit. Impersonating a lower-privileged test user is the only reliable way to see the access control behavior real users will actually experience.
Q4
What does an ACL script's answer variable control, and what two things is it commonly combined with?
What does an ACL script's answer variable control, and what two things is it commonly combined with?
Setting answer to true or false in an ACL script directly determines whether that ACL grants access for the record/field being evaluated. It's commonly combined with gs.hasRole() (checking the user's role) and gs.getUserID() compared against a reference field on the record, to express row-level conditions like "only the assigned agent or their manager."