CMa_yfield
ServiceNow Employee

Why Database Security Matters

 

The single most important feature that your custom scoped app must have, is data security. There is no other capability that is more important. Before you begin mocking up cool looking screens, you must FIRST define your data security requirements for your custom scoped app.

 

In 2025, the average cost of a data breach reached $4.44 million globally, with U.S. organizations averaging $10.22 million per breach, the highest of any region. (Source: Secureframe)

 

This guide focuses on custom scoped application security for ServiceNow developers and architects. Platform-level security (instance hardening, TLS) is outside the scope of this article.

 

ACL Fundamentals and Order of Operations

 

Zero-Trust Security Foundation of the ACL engine

 

ServiceNow Access Control Lists (ACLs) operate on a zero-trust cybersecurity framework where access is denied by default and must be explicitly granted. The ACL engine completely denies access if an ACL is empty or invalid.

  • Empty ACLs lack one or more required components: defined role, security attribute, data condition, or script.
  • Invalid ACLs contain roles or security attributes that do not exist in the database, or scripts containing only answer=true or true.

 

This deny-by-default stance ensures that developers (that’s right, I am talking to you!) MUST explicitly define access permissions rather than relying on permissive defaults.

(Source: ServiceNow ACL Documentation)

 

ServiceNow includes wildcard ACLs (using the asterisk (*) character) that apply to any table or field in the system, providing baseline security when no specific ACLs exist for a custom table.

 

The glide.sm.default_mode property enforces wildcard ACL behavior. Deny mode (current default value that cannot be edited) ensures wildcard ACLs restrict operations to admin users only. Allow mode (found in some very old instances not yet hardened by their admins in spite of ServiceNow recommendations) allows wildcard ACLs to permit access to all users.

 

Allow mode is a HUGE security risk. If your instance has this value, it is recommended you update this immediately!

(Source: ServiceNow Default Deny Property)

 

What Are Access Control Lists (ACLs)?

 

Access Control Lists (ACLs) provide role-based access control at the database level in ServiceNow, restricting access to tables, fields, and records. ACLs determine who can create, read, write (update), or delete data based on user roles, record conditions (data values), and custom scripts. Understanding when and how ACLs execute is fundamental to building secure applications.

 

When ACLs Execute

 

  • List views: ACLs evaluate per record displayed. A list view showing 50 records means ACL scripts run 50 times. A dashboard that has 10 bar / donut reports of 1000 records each runs ACL scripts 10*1000 = 10,000 times! Performance optimization is essential, especially if you are using script evaluations!
  • Form opens: Both table-level and field-level ACLs evaluate to determine access.
  • Field access: Individual field-level ACLs provide granular protection for sensitive data.

 

Table-Level vs Field-Level Access Control

 

Think of ACL evaluation like military security clearances. You first need base access clearance (table-level ACL) before your building clearances (field-level ACL) matter. Record ACLs follow a two-gate model where table-level ACLs are evaluated first (gate 1), determining if the user has access to the table itself. Only if the table-level ACL passes does evaluation proceed to field-level ACLs (gate 2). Both gates must pass for the user to access the data on a record.

 

If a user fails the table-level ACL, all fields are denied regardless of field-level permissions—no compartmentalized clearance helps if you can't access the base. If a user passes the table-level ACL but fails a field-level ACL, that specific field becomes inaccessible (does not even show on the screen) while other fields remain visible. (Source: ServiceNow Community - ACL Execution Order)

 

Evaluation Order Within Each ACL: The Security Checkpoint Model

 

Within both table-level and field-level ACLs, ServiceNow evaluates three security checkpoints in a specific sequence, optimized for performance. Think of this as passing through a 3-step security evaluation to enter a secure government building where you have to first scan your ID, then scan your fingerprint, and last enter your PIN:

  1. Checkpoint 1 - Roles (Badge Scan): Fastest evaluation. Roles are cached in server memory, providing instant verification. If the user lacks required roles, evaluation stops immediately and ACCESS IS DENIED—no need to proceed to checkpoints 2 and 3.
  2. Checkpoint 2 – ACL Conditions (Fingerprint Scan): Medium speed evaluation. The system queries the current record's field values, as defined in the custom filter, to verify conditions are met. If all conditions are not met, evaluation stops immediately and ACCESS IS DENIED—no need to proceed to checkpoint 3.
  3. Checkpoint 3 – Scripts (PIN entry): Slowest evaluation. This requires invoking the JavaScript engine for custom logic. CREATE ELEGANT JAVASCRIPT to ensure there are minimal impacts on your app’s performance!

 

This hierarchy saves computational resources. Best practice dictates shielding expensive scripts behind role and condition checks whenever possible. When conditional security requires scripting, keep in mind that you are trading time-consuming script runs for better performance. Remember, when loading a list or dashboard, the ACLs for that table run at least one time per record.

(Source: ServiceNow Community - Order of Execution)

 

Most-Specific to Most-Generic Evaluation Hierarchy for multiple ACLs on the same table

 

When multiple ACLs apply to the same object, ServiceNow evaluates from most specific to most generic, stopping at the first match that grants access.  This is used for conditions where you might want access to be defined at a higher level parent table, using inheritance.

 

For table ACLs, evaluation proceeds:

  1. specific table name (e.g., incident)
  2. parent table name (e.g., task)
  3. wildcard any table (*)

For field ACLs, the hierarchy is more granular:

  1. incident.number (table.field)
  2. task.number (parent.field)
  3. *.number (any table, specific field)
  4. incident.* (specific table, any field)
  5. task.* (parent table, any field)
  6. *.* (any table, any field).

The first successful field ACL evaluation stops processing at the field level. (Source: ServiceNow ACL Processing Order)

 

Remember where I stated for each record represented on a dashboard or list view, the table ACLs will run at least once? Above are examples of where one table can have multiple table and field ACLs. Running multiple ACLs can negatively impact your performance. If you choose to take this route, make sure the business need justifies the performance cost. There are trade-offs here and the custom scoped app stakeholders need to be made aware of this.

 

ACLs will run all the way through (first on the table level, then on the field level) when multiple ACLs exist for evaluation on the same table or set of tables (considering inheritance parent table(s)), until no match for ALLOW is found (unless using Deny-Unless decision type mentioned later in this article). If a user does not have access, the final determination is not made until after all the ACLs run UNLESS the user fails the initial role evaluation.

 

Developers should

  • Define table level ACLs instead of relying on parent evaluation
  • Be aware of parent field level ACLs that might impact your table that was extended from another table (including OOB)
  • Define custom scoped app specific roles instead of relying on system base role (if needed, add role as inherited by another role)
  • Write scripts to return several times throughout, as soon as a true or false decision is made
  • Order evaluation strategically, running simple and/or common evaluations first

 

ACL Operation Types

 

ACLs secure different operations that users can perform on data. Each operation describes a valid action the system can take on the specified object.

 

Core CRUD Operations (Create, Read, Write (Update), Delete):

  • Create: Enables users to insert new records into a table. Users failing create ACLs cannot see the New button on forms or insert records via API.
    • TIP: Users must also have write access to be able to create
  • Read: Enables users to display records from a table. Users failing read ACLs cannot see the object in forms or lists, nor retrieve records via API.
    • TIP: Make sure you have a Before Query Business Rule defined for instances where security applies for users to see some but not all records in a list to avoid the ‘Removed by Security Constraints’ error
  • Write (Update): Enables users to update records in a table. Users failing write ACLs see read-only fields in forms and lists, and cannot update records via API.
  • Delete: Enables users to remove records from a table. Users failing delete ACLs cannot see the Delete button on forms or remove records via API.
    • TIP: If a user needs to cancel a record, this is a write action (e.g., change state field to cancel), not a delete action

 

Query Operations for Sensitive Data Protection:

 

Query ACLs defend against blind query attacks where users attempt to extract information patterns from data they have partial access to view. Two query operation types provide this protection:

  • query_match: Allows safe operators (EQUALS, NOT_EQUALS, IN, NOT_IN, ISEMPTY, ISNOTEMPTY, ISNULL, ISNOTNULL) that fetch specific records without enabling boundary exploration. Users failing query_match ACLs cannot submit these match queries.
  • query_range: Controls dangerous operators (STARTS_WITH, CONTAINS, >=, <=) that allow users to query across boundaries and extract data patterns. Users failing query_range ACLs cannot submit range queries, and sorting by that column is restricted.

 

Military Example - Query ACL Protection:

 

Consider a military operations application where analysts can view classified reports within their security compartment. An analyst with SECRET clearance for European operations can see report summaries for their assigned region (read access granted via standard ACL with conditions ‘Region=Europe’ and ‘classification IsOneOf Secret/CUI/Unclassified’). However, without query_range ACLs, they could execute queries like operation_name STARTS_WITH 'Dragon' or classification_level >= TOP_SECRET to infer information about compartmentalized operations outside their clearance. They might not see the actual report contents, but the query results themselves—number of matches, date ranges, patterns—leak intelligence about operations they are not cleared for.

 

Query_range ACLs prevent these reconnaissance attempts while still allowing legitimate queries like operation_name EQUALS 'Specific Authorized Op' within their authorized compartment. (Source: ServiceNow Query ACLs)

 

Additional Operation Types:

 

ServiceNow supports additional specialized operations:

  • report_on (enables creating reports on tables)
  • report_view (enables viewing report content)
  • list_edit (enables updating records from lists)
  • save_as_template (enables saving records as templates)
  • edit_task_relations (enables defining relationships between task tables)
  • edit_ci_relations (enables defining relationships between Configuration Item tables)
  • personalize_choices (enables configuring table or field choices)
  • add_to_list (prevents viewing or personalizing specific columns)
  • data_fabric (allows data fabric tables to reference local tables)
  • conditional_table_query_range (enables partial ACL access based on read ACLs)

 

Applies To vs Data Condition: Target Zone vs Access Requirements

 

The Applies To field and Data Condition field serve different purposes in ACL configuration.

  • Applies To defines your target zone—which specific records this ACL applies to. If empty, the ACL applies to all records in the table. For example, Applies To: Priority = P1 means this ACL only affects Priority 1 records; the ACL does not even evaluate for P2, P3, or P4 records.
    • Note that Applies To is case sensitive.
  • Data Condition defines the access requirements—what conditions must be true for users to gain access to records already in the ACL's scope. Using the condition builder, you can specify field values that must evaluate to true, such as [Incident state] [is not] [Closed].

 

The distinction: Applies To determines whether the ACL is in play at all; Data Condition determines whether access is granted once the ACL is in play.

(Source: ServiceNow Applies To Behavior)

 

Decision Types: Deny-Unless vs Allow-If

 

ServiceNow provides two decision types for ACLs, introduced in the Xanadu release, that fundamentally change how access is granted. Understanding when to use each type is critical for effective security implementation.

 

Technical Behavior - How They Work:

 

Deny-Unless ACLs are always evaluated first, before any Allow-If ACLs. If a user fails a Deny-Unless check, access is denied immediately—no further rules are checked. However, passing a Deny-Unless ACL does NOT grant access; it simply means the user will not be denied by that specific rule. The user still needs an Allow-If ACL to actually gain access. Multiple Deny-Unless ACLs can exist on the same object, and ALL of them must pass for evaluation to continue. If any Deny-Unless fails, access is blocked.

 

Allow-If ACLs represent the traditional ServiceNow access control model mentioned at the beginning of this article. They work on an additive principle: if ANY matching Allow-If ACL condition is satisfied, access is granted. All existing ACLs were automatically converted to Allow-If ACLs in the Xanadu release without functionality impact. The ACL engine will not grant access unless there is an Allow-If ACL explicitly permitting it. (Sources: ServiceNow Deny-Unless ACL Documentation, Community Discussion)

 

Use Cases - When to Use Each Type:

 

The decision between Deny-Unless and Allow-If often comes down to how many fields need protection. Use Deny-Unless ACLs when you only need to secure a few sensitive attributes. Use Allow-If ACLs when you need to show just a few attributes but restrict access to most others. (Source: ServiceNow Community - Need-to-Know Principle)

 

Example 1 - Deny-Unless (Few Fields to Protect):

 

A personnel records table contains 50 fields including name, rank, assignment, contact information, and duty history. However, only 3 fields contain highly sensitive information: security_clearance_level, classified_assignments, and polygraph_results. Rather than creating 47 Allow-If ACLs for the non-sensitive fields, create 3 Deny-Unless field-level ACLs on the sensitive fields requiring specific roles (e.g., security_officer role). All other fields remain accessible through the standard table-level Allow-If ACL. This approach is simpler and safer—you explicitly lock down what needs protection.

 

Example 2 - Allow-If (Few Fields to Expose):

 

A classified mission planning table contains 40 fields with detailed operational intelligence. Only 4 fields should be visible to junior analysts: mission_name, status, assigned_unit, and timeline_summary. Create Allow-If field-level ACLs on these 4 fields granting access to the junior_analyst role. Set the table-level read ACL to require senior_analyst role. Junior analysts pass the table ACL (can see records exist) and pass the 4 field ACLs (can see those specific fields), but fail ACLs on the remaining 36 sensitive fields, which appear blank or hidden. This exposes only what they need while protecting operational details.

Scripted ACLs for Dynamic Security

When should you use Complex Scripted ACLs?

Role-based ACLs and condition builders handle most security requirements efficiently. However, certain business scenarios demand conditional logic that cannot be expressed through roles and simple conditions alone. When security requirements depend on multiple factors evaluated in sequence, or when access rules involve complex relationships between records, scripted ACLs become necessary.

Business Case: Disciplinary Investigation Security

Consider a disciplinary investigation application where investigations involve sensitive personnel matters. Security requirements dictate that:

  1. Specific individuals must be explicitly excluded from viewing certain investigations regardless of their role or group membership (e.g., the subject of the investigation, conflicted parties, or individuals with personal relationships to involved parties). This exclusion must be evaluated first.
  2. Investigation administrators (members of ‘investigation admins’ group type) must have access to all investigations for oversight and compliance purposes.
  3. Assigned investigators (members of the specific group in the ‘assigned to’ field handle the investigation) must have access to their assigned cases.

This three-tier conditional security cannot be achieved with role-based ACLs alone. Roles cannot evaluate whether a specific user appears in an exclusion list field in a specific investigation record. Conditions cannot check group type membership for the ‘logged-in use’ across multiple groups. This scenario requires a scripted ACL.

Use a Script Include for Reusable Security Logic

Best practice dictates creating a dedicated Script Include to centralize complex security business logic. Have the ACL script fields in your custom scoped app call this Script Include, promoting code reuse and maintainability.

Using our disciplinary investigation example, a Script Include (e.g., Investigation_Security) with a function like canReadInvestigation(record_Id) could implement the three-tier logic required for any investigation record (use investigation record sys_id as the function parameter) or child related record (set record_id parameter with ‘parent’ field value) using if-else conditional statements:

  1. First, call inUserListField (record_Id) to check if the current user appears in the ‘exclusion’ list. If true, return false (deny access).
    • TIP: Notice we are exiting our script right here because there will never be a condition that would allow this person to be able to read the record so there is no need for further evaluation
    •  
  1. Next, call isMemOfGroupType (investigation_admins) to check if the user is a member of any group with the investigation admins type. If true, return true (grant access).
    • TIP: Again, we are exiting our script right here because there will never be a condition that would not allow this person to be able to read the record (that condition was sequenced before this one) so there is no need for further evaluation

 

  1. Finally, call isMemOfGroup (assignedToFieldGroupName) to check if the user belongs to the investigation assigned group. If true, return true (grant access). Otherwise, return false.

The ACL script field for the investigation record contains a single line:

answer = new Investigation_Security().canReadInvestigation (current.sys_id);

This pattern centralizes complex logic, making it reusable across multiple ACLs (read, write, delete operations) and easier to test and maintain.

 

Related List Security Inheritance

 

The disciplinary investigation application could include related tables such as Evidence Records, Interview Notes, and Corrective Actions. If these child tables must inherit the parent investigation case’s security model (very common use case), users who can read the parent investigation should automatically access related evidence and interviews, while users without parent access must not access child records even if they somehow obtain direct links.

 

Implement security cascade using your above Script Include only changing the value passed in the function parameter. In doing this, the parent record is queried and it’s values are used to validate (or deny)  the user’s access to the related child record using the same security functions used to evaluate read access to the parent record. Each related list ACL (Evidence Records, Interview Notes, Corrective Actions) calls the same script include function.  This ensures consistent security enforcement across the parent-child relationship without duplicating security logic for each related table ACLs.

 

The ACL script field for any child, related record to the investigation record would also contains a single line:

answer = new Investigation_Security().canReadInvestigation (current.parent.sys_id);

 

Be Intentional about your script include functions

 

Be as modular as possible in your coding. Create parameters for field names and group names as much as possible, do not create separate functions for each field or group.

Return true or false quickly, don’t continue evaluation if there are no chances the current ‘user gets/is denied access’ value will change.

 

Preserving User Security in Custom Code

ServiceNow ACLs automatically enforce security in server-side scripting contexts. However, certain coding patterns and API calls can bypass ACL enforcement, creating security vulnerabilities. Developers must understand these bypass mechanisms to avoid accidentally exposing sensitive data.

 

Let me remind you that security is the most important ‘feature’ in your custom scoped app. I have seen the below ignored too many times.

 

Critical Service Portal Security Risk: GlideRecord vs GlideRecordSecure

 

GlideRecord in a Service Portal widget server scripts executes with elevated privileges and bypasses ACLs entirely. This is one of the most common and severe security vulnerabilities created by developers who understand AngularJS and MVC coding but did not take the required ServiceNow developer and scripting trainings (these on demand courses are free in ServiceNow University).

 

Service Portal widgets run in a different security context than standard platform scripts which run with as the logged-in user. When developers use GlideRecord in Service Portal server-side scripts, queries return all records regardless of the user’s ACL permissions. Portal users with limited access defined in ACLs can potentially query and retrieve sensitive data they should never see.

 

Always use GlideRecordSecure in Service Portal contexts.

 

GlideRecordSecure enforces user context ACLs (which is why ServiceNow advises using it for all service portal server scripts), ensuring portal users only access data their roles permit.

 

WRONG - Bypasses ACLs:

var gr = new GlideRecord (x_custom_investigation_case);

gr.addQuery(‘classification’ ‘is’ ‘SECRET);

gr.query();

// Returns ALL SECRET investigations regardless of user’s clearance

 

CORRECT - Enforces ACLs:

var gr = new GlideRecordSecure (x_custom_investigation_case);

gr.addQuery(‘classification’ ‘is’ ‘SECRET);

gr.query();

// Returns only investigations the user has ACL permission to access

 

Real-World Scenario 1:

A Service Portal allows employees to submit and view investigation cases. A developer builds a widget showing ‘My Open Investigations’ using GlideRecord to query cases where opened_by = current user to make sure users can only see cases they have opened. However, this would return ALL cases (where opened_by=user) including any case the user might be in the exclusion list for. An employee who is the subject of an investigation (and appears in the excluded_users field) can still see their own investigation case, violating the business requirement that subjects must never access their investigation records. Using GlideRecordSecure would enforce the ACL and properly exclude this case from the user’s returned list of cases they have opened in the service portal widget.

 

Real-World Scenario 2:

A Service Portal allows employees to submit and view investigation cases. A developer builds a widget showing ‘My Open Investigations’ using GlideRecord to query cases where opened_by = current user as the ‘security’ to make sure users can only see cases they have opened. However, if a user URL hacks to /x_custom_investigation_case.list, because there is no ACLs in place, this URL would return ALL cases since no ACLs were applied. An employee who is the subject of an investigation (and appears in the excluded_users field) can still see their own investigation case, plus everyone else’s cases, violating the business requirement that subjects must never access their investigation records.

(Source: ServiceNow Security Documentation)

 

Additional Ways to restrict access to data outside of ACLs

 

There are cases where you might want to limit data that is viewed by a user for simplification reasons, so they are not overwhelmed with having to view all of the data, all at once. You might also want to focus a view at a point in time where some data is more prominent than other data at a specific time during workflow execution. These use cases are related to user experience (UX) and should be addressed in the user interface (UI) at the client level, not at the ACL server level.

 

ServiceNow methods that can perform data abstraction (different than data security) include:

  • UI Policies
  • Data Policies
  • Client Scripts
  • Module/List filters

 

Do not use client side scripting to ‘secure’ data!

 

Also, do not mis-interpret ‘we don’t WANT the user to see’ as ‘the user can NEVER see’ business requirements. Remember there is a trade-off. Dynamic complex business logic for data access costs in performance.

 

 

Conclusion

Effective ServiceNow custom scoped application security requires understanding ACL fundamentals, implementing strategic, elegant scripted security logic when business requirements demand it, and vigilantly avoiding security bypasses in custom code.

Key principles for developers and architects:

  • Define table-level ACLs for custom tables to avoid performance overhead of parent table inheritance.
  • Shield expensive scripts behind role and condition checks to optimize performance. Use Script Includes to centralize complex security logic for maintainability and consistency.
  • Always use GlideRecordSecure in Service Portal server scripts to enforce user context ACLs.
  • Implement related list security inheritance to cascade parent record security to child tables.

With average breach costs exceeding $4.44 million globally and regulatory compliance failures costing organizations $4.62 million on average, robust ACL security is not optional. By following these ACL patterns and principles, understanding evaluation hierarchies, leveraging scripted logic judiciously, and avoiding security bypass pitfalls, developers can build ServiceNow applications that protect sensitive data, meet regulatory and policy compliance requirements, and maintain system performance under production load.

Version history
Last update:
2 hours ago
Updated by:
Contributors