ACLs (Access Control Lists) are the primary security mechanism in ServiceNow. Understanding how they evaluate is essential for both building secure applications and debugging access issues efficiently.
How ACL Evaluation Works
When a user attempts to perform an operation on a record or field, ServiceNow evaluates ACLs in a specific order. Understanding this order explains why some ACLs seem to be ignored.
The evaluation sequence:
- ServiceNow finds all ACLs that match the object being accessed
- ACLs are sorted by specificity — more specific ACLs evaluate before general ones
- The first matching ACL that grants or denies access determines the outcome
- If no ACL matches, access is denied by default (secure by default)
ACL Types
ACLs can be applied at different levels:
- Table-level — controls read/write/create/delete on the entire table
- Field-level — controls read/write on a specific field
- Record-level — controls access based on record data (uses scripts)
The Three Conditions
Each ACL has three conditions that must ALL pass for access to be granted:
- Role — user must have one of the specified roles
- Condition — a filter condition evaluated against the record
- Script — a server-side script that returns true or false
If any one of these conditions fails, the ACL denies access regardless of the others.
Common Pattern: Record Owner Access
// ACL Script: Allow access only to the record's caller
// Table: incident, Operation: write
(function() {
// Allow if user is the caller on the incident
if (current.caller_id == gs.getUserID()) {
return true;
}
// Allow if user has itil role
if (gs.hasRole('itil')) {
return true;
}
return false;
})();
Debugging Access Issues
The fastest way to debug ACL issues is using the Security Debug plugin:
- Navigate to
System Diagnostics > Security - Enter the sys_id of the record the user cannot access
- Enter the user's sys_id
- Select the operation (read, write, etc.)
- Click Evaluate
The output shows exactly which ACL evaluated, in what order, and why access was granted or denied.
Alternatively, add &sysparm_ck_security=true to any URL to see ACL debug output directly on the page.
Common Security Mistakes
1. Over-broad roles in ACLs
Using the admin role as a bypass in ACL scripts is common but dangerous. If admin access is ever expanded, those ACLs expose data you didn't intend to expose.
2. Missing field-level ACLs
Securing the table but not the fields means a user with read access to the table can see all fields including sensitive ones like salary, SSN, or passwords. Always add field-level ACLs for sensitive data.
3. ACL scripts with performance issues
ACL scripts execute on every record access. A script that queries another table runs that query for every single record in a list view. Use gs.hasRole() and current field comparisons rather than GlideRecord queries inside ACL scripts.
4. Not testing as the actual user
Testing ACLs as admin with impersonation is unreliable because admin bypasses many ACL checks. Test in a separate browser session logged in as the actual user or a test account with the exact same roles.
Best Practices
- Create custom roles for your applications rather than using built-in roles
- Document what each custom role grants — add a description to the role record
- Review ACLs during every release — they accumulate technical debt fast
- Never use admin checks in ACL scripts for production access control
- Test ACL changes in a sub-production environment before promoting