Understanding ACLs (Access Control Lists) in Depth
Introduction
Access Control Lists (ACLs) are ServiceNow's primary mechanism for controlling who can read, write, create, or delete data. They sit at the heart of the platform's security model, and misunderstanding them is one of the most common causes of both over-permissive and overly restrictive instances.
This guide covers everything from basic ACL structure to advanced scripted conditions, the evaluation order algorithm, and practical patterns for common enterprise security requirements.
The ServiceNow Security Stack
Before diving into ACLs, understand where they fit in the broader security picture:
1. Roles & Groups — Who you are
2. ACLs — What you can do with records
3. UI Policies — What you see on forms (not security)
4. Business Rules — Data integrity logic (not security)
5. Data Policies — Enforce mandatory fields across channels
ACLs are the authoritative gate. UI Policies only hide/show fields in the browser—they offer no real protection.
ACL Structure: The Four Elements
Every ACL is defined by four attributes:
1. Operation
What action is being controlled:
read— Can the user see this record or field?write— Can the user edit this field?create— Can the user insert new records?delete— Can the user delete records?execute— For UI Actions and client-callable Script Includes
2. Object Type
- Table-level: Controls access to entire records (e.g.,
incident) - Field-level: Controls access to specific fields (e.g.,
incident.salary_band) - Record-level: Scripted conditions that evaluate per-record (e.g., only the assigned user can edit)
3. Roles
List of roles that grant access. If a user has ANY of the listed roles, this criteria passes.
4. Condition / Script
Optional. Evaluated after role check. Both must pass for access to be granted.
ACL Evaluation Order: How ServiceNow Decides
ServiceNow evaluates ACLs in a specific order of specificity. The most specific matching ACL wins:
Specificity Order (most → least):
1. table.field (e.g., incident.short_description)
2. table.* (e.g., incident.*)
3. *.field (e.g., *.salary)
4. *.* (global fallback)
If NO ACL matches a given operation, access defaults to DENY when the glide.security.strict_mode property is true (recommended for production).
The Evaluation Algorithm
For each ACL that matches the object/operation:
1. Is the user an admin? → GRANT (admins bypass ACLs by default)
2. Does the user have the required role(s)? → Check condition/script
3. Does the condition/script return true? → GRANT
4. If multiple ACLs match: ANY single passing ACL grants access
5. If no ACL passes: DENY
Critical insight: Multiple matching ACLs use OR logic. The user only needs ONE to pass.
Practical ACL Examples
Example 1: Protect a Sensitive Field
Prevent anyone without the hr_manager role from reading salary information:
- Type: Field
- Name:
hr_case.salary_amount - Operation:
read - Roles:
hr_manager - Script: (empty — role check is sufficient)
Example 2: Record-Level Ownership ACL
Allow users to edit only incidents assigned to them:
- Type: Record
- Name:
incident - Operation:
write - Roles:
itil - Script:
// Only the assigned user OR their manager can write
answer = (current.assigned_to == gs.getUserID()) ||
gs.hasRole('itil_admin');
Example 3: Time-Based Access
Allow record creation only during business hours:
var now = new GlideDateTime();
var hour = parseInt(now.getLocalTime().getByFormat('HH'));
var dayOfWeek = now.getDayOfWeekLocalTime(); // 1=Sunday, 7=Saturday
// Allow Mon-Fri, 8am-6pm local time
answer = (dayOfWeek >= 2 && dayOfWeek <= 6) &&
(hour >= 8 && hour < 18);
Example 4: Department-Based Visibility
Users can only read HR cases from their own department:
var user = gs.getUser();
var userDept = user.getDepartmentID();
answer = (current.department == userDept);
The answer Variable
In scripted ACLs, you control access by setting the answer variable:
// Grant access
answer = true;
// Deny access
answer = false;
// Conditional — check if user is in a specific group
var grpMember = new GlideRecord('sys_user_grmember');
grpMember.addQuery('group.name', 'Network Operations');
grpMember.addQuery('user', gs.getUserID());
grpMember.query();
answer = grpMember.hasNext();
ACL Debugging Tools
1. Security Debug Plugin
Enable via System Diagnostics > Session Debug > Security:
- Navigate to a record and observe the console for detailed ACL evaluation messages.
- See exactly which ACL evaluated, what the result was, and why.
2. Access Control Simulator (Washington DC+)
Go to System Security > Access Control List > Simulate Access to test ACL evaluation for any user/record/operation combination without impersonating.
3. Impersonation
Use System Settings > Impersonate User to temporarily act as another user and observe what they can and cannot see.
Common ACL Anti-Patterns
Anti-Pattern 1: Relying on UI Policies for Security
❌ Wrong: "We use a UI Policy to hide the salary field."
✅ Right: Add a field-level read ACL on salary. UI Policies can be bypassed.
Anti-Pattern 2: Admin Everywhere
❌ Wrong: Granting admin role to bypass ACL issues during development.
✅ Right: Debug the ACL, fix the permission model, use security debug tools.
Anti-Pattern 3: Overly Expensive ACL Scripts
// ❌ This fires on EVERY record in a list — catastrophic for performance
answer = (function(){
var gr = new GlideRecord('incident');
gr.query(); // Full table scan in every ACL evaluation!
return gr.getRowCount() > 0;
})();
// ✅ Use current object or gs APIs that are already cached
answer = current.assigned_to == gs.getUserID();
Anti-Pattern 4: Missing Delete ACLs
Many teams configure read/write/create but forget delete. This often results in either everyone being able to delete records or no one being able to.
Best Practices Checklist
- Enable
glide.security.strict_modein production - Create explicit ACLs for every sensitive table operation
- Always add field-level ACLs for PII, salary, health, and credential fields
- Keep ACL scripts lightweight — avoid GlideRecord queries when possible
- Document the purpose of every non-trivial scripted ACL
- Test ACLs with security debug before deploying
- Use the ACL simulator to validate new roles before go-live
- Review ACLs after every major platform upgrade
- Never use
gs.hasRole('admin')as the sole condition — it's a bypass, not a grant
Conclusion
ACLs are the backbone of ServiceNow security. Understanding their evaluation order, the four elements of every ACL, and the subtle power of scripted conditions gives you the tools to build a genuinely secure instance. Pair strong ACLs with Data Policies for mandatory field enforcement and avoid the temptation to use UI Policies as a substitute for real access control.