Week 7: Access Control: ACLs, Roles & the Security Model

Every read and write you've been doing all course has been running as the admin role, which quietly bypasses most restrictions. This week is where you learn how ServiceNow actually decides who can see and touch what — knowledge that becomes essential the moment you build anything meant for non-admin users.

Module 7 of 25 Week 7 of 26 ~3–4 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Explain how table-level, field-level and row-level ACLs interact
  • Write an ACL script using gs.hasRole() for conditional access
  • Diagnose "why can't this user see this record" using the security debugger

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.

ACLs are deny-by-default, additively granted

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.

conceptual ACL configuration
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.

ACL script — incident, write, row-level condition
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

Hands-on

Restrict write access to a custom field by role

Requirements:

  1. Add a custom field u_internal_notes to the incident table.
  2. Create a field-level write ACL on it requiring the itil_admin role (so regular itil agents can read but not write it).
  3. Create a non-admin test user with only the itil role, and impersonate them to confirm the field is visible but read-only.
  4. 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.
Hint

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?

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"?

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?

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?

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."