Most ServiceNow security reviews check the obvious: password policies, role assignments, encryption at rest. After years of hands-on platform security assessments across 100+ instances, the real risk lives in configurations that auditors don't know to look for.
Here are 10 gaps I find in nearly every instance I review.
1. ACLs That Silently Fail Open
When no ACL matches a request, ServiceNow's default behavior is controlled by glide.security.no_acl.default. Most instances leave it at the default — which means unprotected tables are accessible via direct URL or API.
The danger isn't the tables you know about. It's the custom tables a developer created six months ago without thinking about access control. One GlideRecord query from a public-facing portal widget, and that data is exposed.
What to check:
// Find tables with no ACL protection
var gr = new GlideRecord('sys_db_object');
gr.addQuery('super_class', '');
gr.query();
while (gr.next()) {
var acl = new GlideRecord('sys_security_acl');
acl.addQuery('name', gr.getValue('name'));
acl.query();
if (!acl.hasNext()) {
gs.info('No ACL: ' + gr.getValue('name'));
}
}
Fix: Set glide.security.no_acl.default to false. Then audit every table with the script above and create explicit deny-all baselines.
2. REST API Endpoints Exposed Without Proper Auth
Developers create Scripted REST APIs and Table API access points all the time. Most of them work fine functionally. But check how many require authentication.
Query sys_ws_operation and filter on requires_authentication = false. You'll almost certainly find endpoints that return data to unauthenticated callers — including endpoints that were "temporary" two years ago.
The Table API is even worse. By default, any authenticated user can query most tables via /api/now/table/{tablename}. The ACL system protects the data, but only if ACLs exist (see Gap #1).
Fix: Enforce OAuth 2.0 or token-based auth on all custom REST endpoints. Audit the Table API scope with sys_rest_api_access rules.
3. System Properties Left in Debug Mode
After a go-live, debug properties tend to stay active. These are the ones I check first:
glide.security.use_csrf_token— if disabled, every form on your instance is vulnerable to CSRFglide.security.debug.role— logs role evaluation details that can leak internal role structuresglide.ui.session_timeout— often set to absurd values during developmentglide.servlet.uri— misconfigured instances expose internal hostnames
What to check:
var props = ['glide.security.use_csrf_token', 'glide.security.debug.role',
'glide.security.debug.acl', 'glide.ui.session_timeout'];
props.forEach(function(p) {
gs.info(p + ' = ' + gs.getProperty(p));
});
Fix: Create a hardening baseline for security-relevant properties. Review after every upgrade and every clone.
4. Over-Privileged Integration Users
This is the most common finding across every assessment I run. The pattern is always the same: a developer needed an integration account to work with a MID Server, Splunk, or a third-party tool. They gave it admin because "it was easier." That was 18 months ago.
Now you have 6-12 service accounts with admin or security_admin, each with a static password, each capable of reading every record in your instance.
What to check:
var gr = new GlideRecord('sys_user_has_role');
gr.addQuery('role.name', 'admin');
gr.addQuery('user.active', true);
gr.addQuery('user.last_login', '<', gs.daysAgoStart(90));
gr.query();
gs.info('Admin users not logged in for 90+ days: ' + gr.getRowCount());
Fix: Dedicated roles per integration. No shared accounts. OAuth where possible. Rotate credentials on a schedule.
5. Client-Side Business Rules Leaking Data
Display Business Rules run on the client. They have access to server-side data via GlideRecord, and they push results to the browser via g_scratchpad. The problem: developers use them as a convenient way to pass data to the UI without thinking about what that data contains.
I've seen Display Business Rules that expose internal IP addresses, integration credentials stored in system properties, and full user records including email and phone for users the current session shouldn't be able to see.
Fix: Audit every Display Business Rule. Move sensitive logic server-side. Treat g_scratchpad as a public API — anything you put there, assume an attacker can read.
6. Unprotected Knowledge Base and Catalog Items
Knowledge articles with internal runbooks, architecture diagrams, or credentials. Catalog items with variables that expose infrastructure details. These are surprisingly common because the people who create KB articles aren't thinking about access control — they're thinking about documentation.
User Criteria is the gatekeeper, but it's only effective if someone actually configures and tests it. Most orgs set it once during implementation and never review it.
Fix: Quarterly access review of all KB knowledge bases and their User Criteria. Test from an external user's perspective — log in as a portal user and see what you can see.
7. Impersonation Without Audit Trail
Admin impersonation is a legitimate feature. It's also a way for an insider to act as any user without accountability — unless logging is enabled.
Check glide.ui.impersonate.log. If it's not set to true, impersonation events aren't captured. An admin can impersonate a payroll approver, approve a transaction, and there's no record of the impersonation.
Fix: Enable glide.ui.impersonate.log. Create a scheduled job that alerts on impersonation of users with security_admin, admin, or any approval-related role.
8. Email Security Misconfigurations
Inbound email actions can execute server-side scripts based on incoming email content. If sender verification isn't configured, an attacker can send a crafted email to your instance's inbound email address and trigger script execution.
Outbound is risky too. Notification templates that include sys_id values or direct instance URLs give attackers a map of your data structure.
Fix: Always validate the sender in inbound email actions. Strip internal identifiers from outbound notification templates. Review sysevent_email_action for any entries that execute scripts without sender conditions.
9. Update Sets and Clone Hygiene
Two patterns I see repeatedly:
Update sets with secrets: Developers hardcode API keys, passwords, or tokens in Script Includes or Business Rules. These get captured in update sets and promoted across environments. Now your production credentials exist in dev, test, and whoever got a copy of that update set.
Cloning without sanitization: Production gets cloned to sub-prod for testing. All credentials, OAuth tokens, and integration configurations come along. Sub-prod environments typically have weaker access controls, wider access, and less monitoring.
Fix: Use Data Preservers for credentials during clone operations. Implement an update set review process that checks for hardcoded secrets before promotion.
10. No Visibility Into What Actually Changed
This is the meta-gap. Most orgs rely on sys_audit for change detection, but sys_audit has significant blind spots:
- ACL changes aren't always captured
- System property modifications may not generate audit entries
- Role escalations through group membership changes can fly under the radar
- Script Include modifications that change security behavior don't trigger alerts
You can pass a SOC 2 audit with sys_audit alone. But you can't detect a sophisticated insider threat or a compromised admin account.
Fix: Purpose-built change detection that goes beyond native audit. Monitor ACL modifications, role changes, property updates, and Script Include edits as security events — not just configuration changes.
The Common Thread
Every one of these gaps exists in production instances right now — many of them in organizations that passed their last SOC 2 or ISO 27001 audit. The common thread: auditors check what the compliance framework tells them to check, not what attackers actually exploit.
If you want to map your own blind spots, that's exactly the kind of assessment I built Nowisor to deliver. Ask a question about your instance's security posture, and get back real attack paths — not a generic checklist.
Rachid Harrando is a cybersecurity consultant specialized in ServiceNow platform security, a Black Hat Arsenal Review Board member, and the founder of Nowisor. He previously served as Principal Security Advisor at ServiceNow.