5 Ways to Check your ServiceNow Instance for DANGEROUS CODE in Less Than 5 minutes

Your ServiceNow instance DEFINITELY has DANGEROUS CODE executing in it RIGHT NOW, causing performance issues, unexpected behavior, and hiding records from people who should be able to see them (including you)!

This isn't a fear-mongering tactic; it's a fact we all overlook - until it's too late.

In this article, we'll unveil the top five (+1) quick and efficient methods to uncover this concealed, risky, and performance-degrading code in your instance. But that's not all - we'll also shed light on other lurking risks that could be silently sabotaging your instance's performance or security - even as you read this! (These issues even apply in many out-of-box scripts and records!)


1️⃣ Query Business Rules that could be hiding records from you, without your knowledge!

As I mention in this article, your Query Business Rules could be filtering records without your knowledge!
Find any dangerous QBRs by navigating to the sys_script table, filtering that table using the below query, and looking through the returned BRs for any that filter records using "is not", "not in", "!=", etc. queries *without* an "...or is blank" condition.

scriptLIKENOT IN^ORscriptLIKENOTIN^ORscriptLIKEISNOT^ORscriptLIKE, '!='^ORscriptLIKE, "!="^action_query=true


2️⃣ ACL Scripts that execute when they shouldn't!

As I mention in another article, un-checking the "Advanced" checkbox on an ACL rule HIDES the Script field, but it DOES NOT CLEAR IT, and does not prevent the script from running! This can have serious impacts on performance, stability, and can cause unexpected behavior and make these issues incredibly difficult to troubleshoot. I GUARANTEE that you've got at least a couple DOZEN ACLs in your instance RIGHT NOW, with this issue!

The free tool I mention in the article linked above can identify ACLs with this issue and prevent it from occurring in the future, but you can identify ACLs already hiding in your ServiceNow environment right now, by navigating to the sys_security_acl table and using the following query:

advanced=false^scriptISNOTEMPTY

Note: The same thing applies to Business Rules. See the article linked above for more details. It does not, however, apply to UI Policy Scripts. If a UIP's "Run Scripts" field is set to false, then the script will not run.


3️⃣ Tracked Configuration Files exposing your passwords, API tokens, and secret keys!

The "Tracked Configuration files" table in ServiceNow contains copies of the contents of discovered servers' configuration files. While it's not "best-practice", it is very common for .config files to contain API keys, access tokens, or passwords in plain text. When ServiceNow gobbles up this information, it is stored in plain text in a table called cmdb_ci_config_file_tracked.
Depending on your instance version, the content of these files may even be visible to everyone with the itil role! (Although on more recent versions of ServiceNow, it requires a separate role: tracked_file_reader; but the data is still not encrypted, and thus is still something to be wary of).

You can find most of these dangerous tracked config files by navigating to the cmdb_ci_config_file_tracked table, and using a query similar to the following:

contentLIKEtoken^ORcontentLIKEkey^ORcontentLIKEpwd^ORcontentLIKEpassword^ORcontentLIKEsecret^ORcontentLIKEauth

Note: When filtering the table on the "content" field, you'll notice that the "...contains..." query operator is not available in the filter builder. This is annoying, but we can work around it by constructing our own encoded query and using the LIKE operator, then manipulating the URL to use our custom encoded query.


4️⃣ Inefficient client-side queries and GlideAjax calls

Queries and GlideAjax calls in client scripts should always be asynchronous.
You can identify synchronous client-side queries and GlideAjax calls in Client Scripts, Catalog Client Scripts, and UI Policy scripts by navigating to those respective tables and filtering to show records where the script field contains “.query()”, “.get(‘”, or “.getXMLWait(”.
For example, in the sys_script_client table, you can use the following encoded query as a starting point:

scriptLIKE.query()^ORscriptLIKE.get('^ORscriptLIKE.getXMLWait(

Here are some relevant articles to help you get around the need to perform queries or GlideAjax calls synchronously, such as in onSubmit client scripts, and to DRASTICALLY improve performance over the existing out-of-box client-side GlideRecord class:

  1. Performing asynchronous queries in onSubmit ServiceNow Client Scripts or Catalog Client Scripts

  2. A better, MUCH more efficient client-side GlideRecord class

  3. How to debug ServiceNow Client Scripts, UI Policy Scripts, and Catalog Client Scripts in your browser


5️⃣ current.update() in Business Rules

This one won’t be news to most of you, but using current.update() in Business Rules in ServiceNow is pretty much universally a bad idea.
If you need to update the current record, you should be making any necessary changes in a before Business Rule. If you need to update other records that would be displayed in the form or related lists on the current record, you should do so in an after Business Rule. If you need to update some peripheral record that isn't shown in the form of the record that triggered the Business Rule, then you should typically use an async Business Rule.

In none of these scenarios, should you ever use current.update().

Search your Business Rules table (sys_script) for any records where the Script field contains current.update( to identify BRs with this issue.


Bonus tip: Using .getRowCount() instead of GlideAggregate!

There are legitimate uses for the .getRowCount() API method of GlideRecord, but they are relatively rare when it comes to production code.

Search all of your scripts for instances of scripts using GlideRecord's .getRowCount() method, and try to identify which instances of it can be replaced with a GlideAggregate query instead. This is usually the case when the main function of the GlideRecord query is just to get the row count, which is much, much slower using GlideRecord than GlideAggregate.


Do you know of any major risks in ServiceNow that people should be made aware of? Let us know in the comments below!
If you see someone with some helpful ideas in the comments, be sure to drop them a like!

If you like my content, be sure to subscribe to the SN Pro Tips newsletter on snprotips.com, and subscribe on LinkedIn!