ServiceNow Hardening Guide
Enterprise IT platform security for workflows, integrations, and access control lists
Overview
ServiceNow is the dominant IT Service Management (ITSM) platform, commanding 44.4% market share with 85% of Fortune 500 as customers. The ServiceNow Store hosts hundreds of certified apps with deep platform access, while the Configuration Management Database (CMDB) provides attackers with complete infrastructure mapping for lateral movement. Integration credentials stored in IntegrationHub create concentrated supply chain risk.
Intended Audience
- Security engineers hardening ServiceNow instances
- IT administrators managing ServiceNow configurations
- GRC professionals assessing ITSM security
- Third-party risk managers evaluating ServiceNow integrations
How to Use This Guide
- L1 (Baseline): Essential controls for all organizations
- L2 (Hardened): Enhanced controls for security-sensitive environments
- L3 (Maximum Security): Strictest controls for regulated industries
Scope
This guide covers ServiceNow-specific security configurations including authentication, OAuth governance, Store app security, CMDB access controls, and IntegrationHub hardening.
Table of Contents
- Authentication & Access Controls
- Network Access Controls
- OAuth & Integration Security
- CMDB Security
- Store App Security
- Monitoring & Detection
- Compliance Quick Reference
1. Authentication & Access Controls
1.1 Enforce Multi-Factor Authentication
Profile Level: L1 (Baseline) CIS Controls: 6.3, 6.5 NIST 800-53: IA-2(1), IA-2(2)
Description
Require MFA for all ServiceNow user authentication, especially for administrators and users with elevated CMDB access.
Rationale
Why This Matters:
- ServiceNow contains infrastructure blueprints (CMDB) valuable for attack planning
- Credential stuffing attacks target ITSM platforms for initial access
- Admin accounts control workflow automation affecting entire organizations
Attack Prevented: Credential stuffing, password spray, account takeover
Attack Scenario: Compromised ServiceNow admin account modifies change workflows to auto-approve malicious changes
ClickOps Implementation
Step 1: Configure MFA Plugin
- Navigate to: System Definition → Plugins
- Search for: “Multi-Factor Authentication”
- Activate the plugin
- Navigate to: Multi-Factor Authentication → Properties
Step 2: Configure MFA Policies
- Navigate to: Multi-Factor Authentication → MFA Policies
- Create policy:
- Name: “Require MFA for All Users”
- Condition: All users
- Factors: TOTP, Push notification, or FIDO2
- Create stricter policy for admins:
- Name: “Admin MFA”
- Condition: User has admin role
- Factors: FIDO2 required
Step 3: Enable for SSO (if using IdP)
- Navigate to: Multi-Provider SSO → Identity Providers
- Edit your IdP configuration
- Enable: Enforce MFA through IdP
Code Implementation
// ServiceNow Script Include - Enforce MFA Check
var MFAEnforcement = Class.create();
MFAEnforcement.prototype = {
initialize: function() {},
requireMFA: function(userId) {
var gr = new GlideRecord('sys_user');
if (gr.get(userId)) {
// Check if user has admin role
if (gr.hasRole('admin')) {
return this._enforceFIDO2(userId);
}
return this._enforceStandardMFA(userId);
}
return false;
},
_enforceFIDO2: function(userId) {
// Implementation for FIDO2 enforcement
gs.info('FIDO2 MFA required for admin: ' + userId);
return true;
},
type: 'MFAEnforcement'
};
Compliance Mappings
| Framework | Control ID | Control Description |
|---|---|---|
| SOC 2 | CC6.1 | Logical access controls |
| NIST 800-53 | IA-2(1) | Multi-factor authentication |
| ISO 27001 | A.9.4.2 | Secure log-on procedures |
1.2 Implement Role-Based Access Control for CMDB
Profile Level: L1 (Baseline) CIS Controls: 6.8 NIST 800-53: AC-3, AC-6
Description
Restrict CMDB access using granular ACLs. Users should only access configuration items relevant to their role.
Rationale
Why This Matters:
- CMDB contains complete infrastructure topology
- Attackers use CMDB data to identify high-value targets
- Unrestricted CMDB access enables reconnaissance
Attack Scenario: Compromised Store app accesses CMDB to identify privileged systems; stolen integration credentials enable pivot to connected security tools.
ClickOps Implementation
Step 1: Audit Current CMDB ACLs
- Navigate to: System Security → Access Control (ACL)
- Filter by: Table = “cmdb_ci” and related tables
- Document current permissions
Step 2: Create Restrictive CMDB Roles
- Navigate to: User Administration → Roles
- Create roles:
cmdb_read_network- Read network CIs onlycmdb_read_servers- Read server CIs onlycmdb_write_owned- Write to owned CIs only
Step 3: Apply ACLs
- Create ACL for cmdb_ci table:
- Operation: Read
- Role: cmdb_read_network OR cmdb_read_servers
- Condition: Script-based filtering by CI class
- Remove
itilrole from broad CMDB access
// ACL Script for CMDB CI visibility
// Only show CIs the user is authorized to see
answer = (function() {
var userRoles = gs.getUser().getRoles();
if (userRoles.indexOf('cmdb_admin') > -1) {
return true; // Admins see all
}
if (userRoles.indexOf('cmdb_read_network') > -1) {
return current.sys_class_name.toString().startsWith('cmdb_ci_network');
}
return false;
})();
1.3 Restrict High-Privilege Roles
Profile Level: L1 (Baseline) NIST 800-53: AC-6(1), AC-6(5)
Description
Limit assignment of high-privilege roles (admin, security_admin, workflow_admin) and implement approval workflows.
ClickOps Implementation
Step 1: Audit High-Privilege Role Assignments
- Navigate to: User Administration → Users
- Export users with admin roles:
var gr = new GlideRecord('sys_user_has_role'); gr.addQuery('role.name', 'CONTAINS', 'admin'); gr.query(); while (gr.next()) { gs.info(gr.user.user_name + ' has role: ' + gr.role.name); }
Step 2: Create Role Request Workflow
- Navigate to: Workflow → Workflow Editor
- Create approval workflow for admin role requests
- Require multiple approvers for high-privilege roles
- Link to role request catalog item
Step 3: Enable Role Separation
- Prevent users from having conflicting roles:
security_admin+system_admin= Conflictworkflow_admin+impersonator= Conflict
- Implement via Business Rule on sys_user_has_role
2. Network Access Controls
2.1 Configure IP Access Control Lists
Profile Level: L1 (Baseline) CIS Controls: 13.3 NIST 800-53: AC-3, SC-7
Description
Restrict ServiceNow access to known IP ranges (corporate network, VPN, approved integration IPs).
ClickOps Implementation
Step 1: Enable IP Access Control
- Navigate to: System Properties → Security
- Set
glide.security.ip.acl.enabled= true
Step 2: Configure IP Ranges
- Navigate to: System Security → IP Address Access Control
- Add rules:
- Corporate Network: Allow
- VPN Egress: Allow
- Integration IPs: Allow (per-integration)
- Default: Deny
Step 3: Create Integration-Specific Rules For each third-party integration:
- Document integration’s egress IPs
- Create specific ACL rule
- Apply to integration user account
Code Implementation
// Script Include for IP Validation
var IPAccessControl = Class.create();
IPAccessControl.prototype = {
initialize: function() {},
validateAccess: function(clientIP, integrationType) {
var allowedIPs = this._getIntegrationIPs(integrationType);
return allowedIPs.indexOf(clientIP) > -1;
},
_getIntegrationIPs: function(integrationType) {
var ips = [];
var gr = new GlideRecord('x_integration_ips');
gr.addQuery('integration_type', integrationType);
gr.addActiveQuery();
gr.query();
while (gr.next()) {
ips.push(gr.getValue('ip_address'));
}
return ips;
},
type: 'IPAccessControl'
};
3. OAuth & Integration Security
3.1 Audit and Restrict IntegrationHub Connections
Profile Level: L1 (Baseline) CIS Controls: 6.2 NIST 800-53: AC-6, CM-7
Description
Review all IntegrationHub connections (spokes) and restrict to minimum required permissions. IntegrationHub stores credentials for external systems.
Rationale
Why This Matters:
- IntegrationHub contains credentials for connected systems
- Over 300+ pre-built spokes available
- Compromised IntegrationHub = access to all connected systems
Attack Scenario: Attacker compromises ServiceNow, extracts IntegrationHub credentials, pivots to AWS, Azure, and Jira.
ClickOps Implementation
Step 1: Inventory IntegrationHub Connections
- Navigate to: IntegrationHub → Connections
- Export all active connections
- Document:
- Connected system
- Credential type (OAuth, API key, basic auth)
- Last used date
- Business owner
Step 2: Remove Unused Connections
- Identify connections not used in 90+ days
- Validate with business owners
- Deactivate or delete unused connections
Step 3: Rotate All Credentials
- For each active connection:
- Generate new credentials in target system
- Update ServiceNow connection
- Verify integration functionality
- Document rotation in change management
Step 4: Restrict Connection Access
- Navigate to: IntegrationHub → Connection Aliases
- Configure role-based access:
- Only specific roles can use specific connections
- Prevent developers from accessing production connections
Code Implementation
// Audit IntegrationHub Connections
var gr = new GlideRecord('sys_connection');
gr.addActiveQuery();
gr.query();
var report = [];
while (gr.next()) {
report.push({
name: gr.getValue('name'),
credential_alias: gr.credential_alias.getDisplayValue(),
connection_url: gr.getValue('connection_url'),
sys_updated_on: gr.getValue('sys_updated_on')
});
}
gs.info('IntegrationHub Connections: ' + JSON.stringify(report, null, 2));
3.2 Implement OAuth Token Policies
Profile Level: L1 (Baseline) NIST 800-53: IA-5(13)
Description
Configure OAuth token expiration and refresh policies for external integrations accessing ServiceNow APIs.
ClickOps Implementation
Step 1: Review OAuth Applications
- Navigate to: System OAuth → Application Registry
- Document all OAuth clients
- Identify clients with
refresh_tokengrant
Step 2: Configure Token Expiration
- Edit each OAuth application:
- Access Token Lifespan: 3600 (1 hour)
- Refresh Token Lifespan: 604800 (7 days max)
- Code Lifespan: 300 (5 minutes)
- Disable
refresh_tokenfor clients that don’t need persistent access
Step 3: Implement Token Monitoring
// Monitor for unusual OAuth token patterns
var gr = new GlideRecord('oauth_access_token');
gr.addQuery('sys_created_on', '>', gs.daysAgo(1));
gr.query();
var tokenCounts = {};
while (gr.next()) {
var clientId = gr.getValue('client_id');
tokenCounts[clientId] = (tokenCounts[clientId] || 0) + 1;
}
// Alert if any client has excessive tokens
for (var client in tokenCounts) {
if (tokenCounts[client] > 100) {
gs.warn('Excessive OAuth tokens for client: ' + client);
}
}
4. CMDB Security
4.1 Enable CMDB Query Business Rules
Profile Level: L2 (Hardened) NIST 800-53: AC-3
Description
Implement query business rules to filter CMDB results based on user authorization, preventing unauthorized infrastructure discovery.
ClickOps Implementation
Step 1: Create Before Query Business Rule
- Navigate to: System Definition → Business Rules
- Create new rule:
- Table: cmdb_ci
- When: Before
- Action: Query
- Script:
(function executeRule(current, previous) {
// Skip for admins
if (gs.hasRole('cmdb_admin')) {
return;
}
// Get user's authorized CI groups
var authorizedGroups = getUserAuthorizedCIGroups();
// Add query condition
current.addQuery('support_group', 'IN', authorizedGroups);
})(current, previous);
function getUserAuthorizedCIGroups() {
var groups = [];
var gr = new GlideRecord('sys_user_grmember');
gr.addQuery('user', gs.getUserID());
gr.query();
while (gr.next()) {
groups.push(gr.group.toString());
}
return groups.join(',');
}
4.2 Audit CMDB Relationship Queries
Profile Level: L2 (Hardened)
Description
Log and monitor queries against CMDB relationship tables (cmdb_rel_ci) which reveal infrastructure dependencies.
Rationale
Attack Scenario: Attacker queries CMDB relationships to map dependencies between applications and databases, identifying high-value targets.
ClickOps Implementation
Step 1: Enable Query Logging
- Navigate to: System Diagnostics → Session Debug
- Enable: Database query logging for cmdb_rel_ci
- Configure log rotation and SIEM forwarding
Step 2: Create Alert for Bulk Queries
- Create scheduled job to analyze query patterns
- Alert on:
- Queries returning >1000 relationships
- Queries from non-CMDB-admin users
- Queries during off-hours
5. Store App Security
5.1 Implement Store App Approval Workflow
Profile Level: L1 (Baseline) CIS Controls: 2.3 NIST 800-53: CM-7
Description
Require security review and approval before installing ServiceNow Store applications. Store apps have deep platform access.
Rationale
Why This Matters:
- Store apps run with elevated privileges
- 300+ certified apps with varying security postures
- Malicious or compromised app = full instance access
ClickOps Implementation
Step 1: Enable Store App Governance
- Navigate to: System Applications → Applications
- Configure: Require approval for Store installations
- Create approval workflow with security team review
Step 2: Create App Security Checklist Before approving any Store app:
- Review requested permissions/scopes
- Check vendor security certifications (SOC 2)
- Review app’s update frequency
- Check for known vulnerabilities
- Evaluate data access requirements
Step 3: Monitor Installed Apps
- Navigate to: System Applications → All Available Applications
- Create scheduled report of installed Store apps
- Track: Last update, permissions, usage
5.2 Restrict App Scope Access
Profile Level: L2 (Hardened) NIST 800-53: AC-6
Description
Limit Store app access to specific application scopes, preventing apps from accessing data outside their purpose.
ClickOps Implementation
Step 1: Configure Application Scope
- When installing Store app, review requested scopes
- Create separate scope for each app
- Configure scope ACLs to limit table access
Step 2: Disable Cross-Scope Access
- Navigate to: System Applications → Studio
- For each app, configure:
- Accessible from: This application scope only
- Caller access: Restricted
6. Monitoring & Detection
6.1 Enable Security Incident Response
Profile Level: L1 (Baseline) NIST 800-53: IR-4, IR-5
Description
Configure ServiceNow’s Security Operations module or integrate with SIEM for comprehensive audit logging and alerting.
Detection Use Cases
Anomaly 1: Bulk CMDB Export
// Alert on large CMDB exports
var gr = new GlideRecord('sys_audit');
gr.addQuery('tablename', 'cmdb_ci');
gr.addQuery('action', 'export');
gr.addQuery('sys_created_on', '>', gs.hoursAgo(1));
gr.query();
if (gr.getRowCount() > 10) {
gs.eventQueue('security.cmdb.bulk_export', current,
gr.getRowCount() + ' CMDB exports in last hour');
}
Anomaly 2: IntegrationHub Credential Access
// Alert on credential alias access outside normal hours
var hour = new GlideDateTime().getLocalTime().getHour();
if (hour < 6 || hour > 20) {
gs.eventQueue('security.integration.offhours', current,
'IntegrationHub access during off-hours');
}
Anomaly 3: Admin Role Changes
// Alert on any admin role assignment
current.addAfterBusinessRule(function() {
if (current.role.name.toString().indexOf('admin') > -1) {
gs.eventQueue('security.role.admin_assigned', current,
'Admin role assigned to: ' + current.user.user_name);
}
});
7. Compliance Quick Reference
SOC 2 Trust Services Criteria Mapping
| Control ID | ServiceNow Control | Guide Section |
|---|---|---|
| CC6.1 | MFA enforcement | 1.1 |
| CC6.2 | CMDB role-based access | 1.2 |
| CC6.6 | IP access control | 2.1 |
| CC7.2 | Security monitoring | 6.1 |
NIST 800-53 Rev 5 Mapping
| Control | ServiceNow Control | Guide Section |
|---|---|---|
| IA-2(1) | MFA | 1.1 |
| AC-3 | CMDB ACLs | 1.2, 4.1 |
| AC-6 | Role restrictions | 1.3 |
| CM-7 | Store app approval | 5.1 |
Appendix A: Edition Compatibility
| Control | Standard | Professional | Enterprise |
|---|---|---|---|
| MFA | ✅ | ✅ | ✅ |
| IP ACLs | ✅ | ✅ | ✅ |
| IntegrationHub | Add-on | ✅ | ✅ |
| Security Operations | ❌ | Add-on | ✅ |
| Advanced CMDB | ❌ | ✅ | ✅ |
Appendix B: References
Official ServiceNow Documentation:
Supply Chain Considerations:
- Store apps should be treated as supply chain risk
- IntegrationHub credentials are high-value targets
- CMDB data exposure enables attack planning
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2025-12-14 | 0.1.0 | draft | Initial ServiceNow hardening guide | Claude Code (Opus 4.5) |