v0.1.0-draft AI Drafted

ServiceNow Hardening Guide

IT Operations Last updated: 2025-02-05

IT service management platform hardening for ServiceNow including SSO configuration, Security Center, and high-security plugins

Overview

ServiceNow is a leading IT service management and business workflow platform used by thousands of enterprises worldwide. As a platform managing critical IT operations and business processes, ServiceNow security configurations directly impact operational integrity.

Intended Audience

  • Security engineers managing ITSM platforms
  • IT administrators configuring ServiceNow
  • GRC professionals assessing IT operations security
  • Platform administrators managing instance security

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 instance security including SAML SSO, Security Center, high-security plugins, and RBAC.


Table of Contents

  1. Authentication & SSO
  2. Security Center & Hardening
  3. Access Controls
  4. Monitoring & Compliance
  5. Compliance Quick Reference

1. Authentication & SSO

1.1 Configure SAML Single Sign-On

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 6.3, 12.5
NIST 800-53 IA-2, IA-8

Description

Configure SAML SSO to centralize authentication for ServiceNow users.

Rationale

Why This Matters:

  • ServiceNow recommends SSO with SAML or OIDC
  • Enables organizational MFA enforcement
  • Required for enterprise security

Prerequisites

  • ServiceNow admin access
  • SAML 2.0 or OIDC compatible IdP
  • Multi-Provider SSO plugin activated

ClickOps Implementation

Step 1: Activate Multi-Provider SSO

  1. Navigate to: System DefinitionPlugins
  2. Search for Multi-Provider SSO
  3. Activate plugin if not enabled

Step 2: Create SAML Configuration

  1. Navigate to: Multi-Provider SSOIdentity Providers
  2. Click New
  3. Select SAML as the type

Step 3: Configure IdP Settings

  1. Enter IdP metadata
  2. Use your own certificates (recommended)
  3. FIPS mode requires separate Encryption and Signing certificates

Time to Complete: ~2 hours


Code Pack: API Script
hth-servicenow-1.01-configure-saml-sso.sh View source on GitHub ↗
info "1.1 Checking Multi-Provider SSO plugin status..."
SSO_PLUGIN=$(sn_table_get "sys_plugins" \
  "sysparm_query=id=com.snc.integration.sso.multi&sysparm_fields=id,active" \
  | jq -r '.result[0].active // empty' 2>/dev/null || true)

if [ "${SSO_PLUGIN}" = "active" ]; then
  pass "1.1 Multi-Provider SSO plugin is active"
else
  fail "1.1 Multi-Provider SSO plugin is NOT active — enable via Plugins"
  increment_failed
fi
info "1.1 Checking SSO properties..."
SSO_ENABLED=$(sn_table_get "sys_properties" \
  "sysparm_query=name=glide.authenticate.sso.redirect.url&sysparm_fields=name,value" \
  | jq -r '.result[0].value // empty' 2>/dev/null || true)

if [ -n "${SSO_ENABLED}" ]; then
  pass "1.1 SAML SSO redirect URL is configured: ${SSO_ENABLED}"
else
  warn "1.1 SAML SSO redirect URL not found — SSO may not be configured"
fi

# Verify SAML 2.0 IdP records exist
IDP_COUNT=$(sn_table_get "sso_properties" \
  "sysparm_query=protocol=saml2&sysparm_fields=name,protocol,is_default" \
  | jq -r '.result | length' 2>/dev/null || echo "0")

if [ "${IDP_COUNT}" -gt 0 ]; then
  pass "1.1 Found ${IDP_COUNT} SAML 2.0 Identity Provider configuration(s)"
  increment_applied
else
  fail "1.1 No SAML 2.0 IdP configurations found — configure SSO in Multi-Provider SSO"
  increment_failed
fi

1.2 Configure Account Recovery Administrator

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 5.4
NIST 800-53 AC-6

Description

Configure Account Recovery (ACR) administrator for SSO fallback.

Rationale

Why This Matters:

  • ACR provides fallback when SSO fails
  • Must be registered before SSO activation

ClickOps Implementation

Step 1: Register ACR Administrator

  1. Before enabling SSO, register ACR admin
  2. Navigate to: System SecurityAccount Recovery

Step 2: Configure ACR Settings

  1. Enable MFA for ACR users
  2. Restrict ACR to authorized personnel only
  3. Document ACR procedures

1.3 Enable Multi-Factor Authentication

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 6.5
NIST 800-53 IA-2(1)

Description

Enforce MFA for all authentication methods.

ClickOps Implementation

Step 1: Verify MFA Settings

  1. MFA enabled by default for local logins
  2. Navigate to: System SecurityMulti-factor Authentication

Step 2: Configure via IdP (SSO)

  1. Enable MFA in identity provider
  2. Use phishing-resistant methods for admins (PIV/CAC, FIDO2)

2. Security Center & Hardening

2.1 Configure Security Center

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-6

Description

Use Security Center to monitor and improve instance security.

ClickOps Implementation

Step 1: Access Security Center

  1. Navigate to: Security Center
  2. Review overall security score

Step 2: Review Hardening Settings

  1. Review hardening compliance score
  2. Determine alignment with SSC recommendations

Step 3: Address Findings

  1. Test fixes in sub-production first
  2. Document accepted risks

2.2 Enable High-Security Plugins

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-6

Description

Activate high-security plugins for enhanced protection.

ClickOps Implementation

Step 1: Verify Plugin Status

  1. Navigate to: System DefinitionPlugins
  2. Search for high-security plugins

Step 2: Enable High-Security Settings

  1. Plugin enables:
    • Centralized security settings
    • Security administrator role
    • Default deny for ACLs

Code Pack: API Script
hth-servicenow-2.02-enable-high-security-plugins.sh View source on GitHub ↗
info "2.2 Checking High Security Settings plugin..."
HS_PLUGIN=$(sn_table_get "sys_plugins" \
  "sysparm_query=id=com.glide.security.high&sysparm_fields=id,active" \
  | jq -r '.result[0].active // empty' 2>/dev/null || true)

if [ "${HS_PLUGIN}" = "active" ]; then
  pass "2.2 High Security Settings plugin is active"
  increment_applied
else
  fail "2.2 High Security Settings plugin is NOT active"
  fail "2.2 Navigate to System Definition > Plugins and activate 'High Security Settings'"
  increment_failed
fi
info "2.2 Checking security system properties..."

check_property() {
  local prop_name="$1"
  local expected="$2"
  local description="$3"

  local value
  value=$(sn_property "${prop_name}")

  if [ "${value}" = "${expected}" ]; then
    pass "2.2 ${description}: ${prop_name}=${value}"
  elif [ -z "${value}" ]; then
    warn "2.2 ${description}: ${prop_name} not set (expected: ${expected})"
  else
    fail "2.2 ${description}: ${prop_name}=${value} (expected: ${expected})"
  fi
}

check_property "glide.security.default.deny" "true" \
  "Default deny ACLs"
check_property "glide.security.use_secure_cookies" "true" \
  "Secure cookies"
check_property "glide.security.strict.xframe" "true" \
  "X-Frame-Options strict mode"
check_property "glide.basicauth.required.user_password" "true" \
  "Require password for basic auth"
check_property "glide.security.csrf_previous.enabled" "true" \
  "CSRF protection"
Code Pack: Sigma Detection Rule
hth-servicenow-2.02-security-property-changed.yml View source on GitHub ↗
detection:
    selection:
        tablename: 'sys_properties'
        fieldname: 'value'
    filter_security_properties:
        documentkey|contains:
            - 'glide.security.default.deny'
            - 'glide.security.use_secure_cookies'
            - 'glide.security.strict.xframe'
            - 'glide.basicauth.required.user_password'
            - 'glide.security.csrf_previous.enabled'
            - 'glide.authenticate.multifactor'
    condition: selection and filter_security_properties
fields:
    - sys_created_on
    - user
    - tablename
    - fieldname
    - oldvalue
    - newvalue
    - documentkey

3. Access Controls

3.1 Configure Role-Based Access Control

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 5.4
NIST 800-53 AC-6

Description

Implement least privilege using ServiceNow’s role model.

ClickOps Implementation

Step 1: Review Role Structure

  1. Navigate to: User AdministrationRoles
  2. Review role hierarchy

Step 2: Apply Least Privilege

  1. Create custom roles for specific functions
  2. Avoid over-assigning admin roles
  3. Use role contains for hierarchies

Step 3: Configure ACLs

  1. Use default deny (high-security plugin)
  2. Create explicit allows

3.2 Limit Admin Access

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 5.4
NIST 800-53 AC-6(1)

Description

Minimize and protect administrator accounts.

ClickOps Implementation

Step 1: Inventory Admin Users

  1. Navigate to: User AdministrationUsers
  2. Filter by admin roles

Step 2: Apply Least Privilege

  1. Limit admin to 2-3 users
  2. Use security_admin for security tasks

Code Pack: API Script
hth-servicenow-3.02-limit-admin-access.sh View source on GitHub ↗
info "3.2 Querying admin role assignments..."
ADMIN_ROLES=$(sn_table_get "sys_user_has_role" \
  "sysparm_query=role.name=admin^state=active&sysparm_fields=user.user_name,user.name,user.active,user.last_login_time" \
  2>/dev/null || true)

ADMIN_COUNT=$(echo "${ADMIN_ROLES}" | jq -r '.result | length' 2>/dev/null || echo "0")

info "3.2 Found ${ADMIN_COUNT} active admin role assignment(s)"

# List each admin
if [ "${ADMIN_COUNT}" -gt 0 ]; then
  echo "${ADMIN_ROLES}" | jq -r '.result[] | "  - \(.["user.user_name"] // "unknown") (\(.["user.name"] // "N/A")) — last login: \(.["user.last_login_time"] // "never")"' 2>/dev/null || true
fi
MAX_ADMINS=5
if [ "${ADMIN_COUNT}" -le "${MAX_ADMINS}" ]; then
  pass "3.2 Admin count (${ADMIN_COUNT}) is within threshold (<= ${MAX_ADMINS})"
  increment_applied
else
  fail "3.2 Excessive admin count: ${ADMIN_COUNT} (threshold: ${MAX_ADMINS})"
  fail "3.2 Review admin assignments and remove unnecessary privileges"
  increment_failed
fi
Code Pack: Sigma Detection Rule
hth-servicenow-3.02-admin-role-granted.yml View source on GitHub ↗
detection:
    selection:
        tablename: 'sys_user_has_role'
        fieldname: 'role'
        newvalue|contains: 'admin'
    condition: selection
fields:
    - sys_created_on
    - user
    - tablename
    - fieldname
    - newvalue
    - documentkey

4. Monitoring & Compliance

4.1 Configure Audit Logging

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 8.2
NIST 800-53 AU-2

Description

Enable and monitor audit logs for security events.

ClickOps Implementation

Step 1: Review Audit Configuration

  1. Navigate to: System LogsAudit
  2. Verify auditing enabled

Step 2: Configure Audit Policies

  1. Audit critical tables
  2. Audit configuration changes
  3. Audit user management

Step 3: Monitor Audit Logs

  1. Create audit dashboards
  2. Set up alerts for suspicious activity

Code Pack: API Script
hth-servicenow-4.01-configure-audit-logging.sh View source on GitHub ↗
info "4.1 Checking audit-related system properties..."

AUDIT_ACTIVE=$(sn_property "glide.sys.audit.active")
if [ "${AUDIT_ACTIVE}" = "true" ]; then
  pass "4.1 System audit is active (glide.sys.audit.active=true)"
  increment_applied
else
  fail "4.1 System audit is NOT active — set glide.sys.audit.active=true"
  increment_failed
fi

AUDIT_DELETE=$(sn_property "glide.sys.audit.delete")
if [ "${AUDIT_DELETE}" = "true" ]; then
  pass "4.1 Delete auditing is enabled (glide.sys.audit.delete=true)"
else
  warn "4.1 Delete auditing is not enabled — set glide.sys.audit.delete=true"
fi

LOGIN_TRACKING=$(sn_property "glide.ui.login_tracking")
if [ "${LOGIN_TRACKING}" = "true" ]; then
  pass "4.1 Login tracking is enabled (glide.ui.login_tracking=true)"
else
  warn "4.1 Login tracking is not enabled — set glide.ui.login_tracking=true"
fi
info "4.1 Querying recent audit log entries..."
RECENT_AUDITS=$(sn_table_get "sys_audit" \
  "sysparm_query=ORDERBYDESCsys_created_on&sysparm_limit=10&sysparm_fields=sys_created_on,user,tablename,fieldname,newvalue,oldvalue" \
  2>/dev/null || true)

AUDIT_COUNT=$(echo "${RECENT_AUDITS}" | jq -r '.result | length' 2>/dev/null || echo "0")

if [ "${AUDIT_COUNT}" -gt 0 ]; then
  pass "4.1 Audit log is operational — found ${AUDIT_COUNT} recent entries"
  info "4.1 Latest audit entries:"
  echo "${RECENT_AUDITS}" | jq -r '.result[:5][] | "  - \(.sys_created_on) | \(.user) | \(.tablename).\(.fieldname) | \(.oldvalue // "-") -> \(.newvalue // "-")"' 2>/dev/null || true
else
  fail "4.1 No recent audit entries found — verify audit configuration"
  increment_failed
fi
Code Pack: Sigma Detection Rule
hth-servicenow-4.01-audit-log-export.yml View source on GitHub ↗
detection:
    selection_audit_access:
        tablename: 'sys_audit'
    selection_deletion:
        tablename: 'sys_audit_delete'
    selection_export:
        tablename|contains: 'sys_audit'
        fieldname: 'export'
    condition: selection_audit_access or selection_deletion or selection_export
fields:
    - sys_created_on
    - user
    - tablename
    - fieldname
    - newvalue
    - oldvalue

5. Compliance Quick Reference

SOC 2 Trust Services Criteria Mapping

Control ID ServiceNow Control Guide Section
CC6.1 SSO/MFA 1.1
CC6.2 RBAC 3.1
CC7.1 Security Center 2.1
CC7.2 Audit logging 4.1

NIST 800-53 Rev 5 Mapping

Control ServiceNow Control Guide Section
IA-2 SSO 1.1
IA-2(1) MFA 1.3
AC-6 Least privilege 3.1
CM-6 Security hardening 2.2
AU-2 Audit logging 4.1

Appendix A: References

Official ServiceNow Documentation:

API & Developer Resources:

Trust & Compliance:

Security Incidents:

  • BodySnatcher / CVE-2025-12420 (October 2025): A critical vulnerability in the ServiceNow Virtual Agent API and Now Assist AI Agents allowed unauthenticated attackers to impersonate any user (including admins) using only an email address, bypassing MFA and SSO. Patched by ServiceNow on October 30, 2025. No evidence of exploitation in the wild.
  • Template Injection CVEs (May 2024): Three vulnerabilities (CVE-2024-4879, CVE-2024-5178, CVE-2024-5217) were patched same day of disclosure but saw in-the-wild exploitation attempts across 6,000+ sites before patching was complete, primarily targeting financial services.

Changelog

Date Version Maturity Changes Author
2025-02-05 0.1.0 draft Initial guide with SSO, Security Center, and access controls Claude Code (Opus 4.5)

Contributing

Found an issue or want to improve this guide?