Probably not enough. ServiceNow ships several logging mechanisms, but out of the box many security-critical events are either not recorded, not retained long enough to cover an investigation, or recorded and never monitored — which is operationally the same as not recorded. The gap that hurts most is retention: by the time a breach is suspected, the window that would have shown the intrusion has usually already rolled off.
What This Is
ServiceNow provides multiple logging mechanisms — sys_audit, syslog, syslog_transaction, sys_security_acl_log, and login tracking tables. However, by default, many security-critical events are either not logged, not retained long enough, or not monitored for anomalies.
Without proper logging, you cannot detect:
- Unauthorized data access (even if ACLs are misconfigured)
- Privilege escalation (new admin accounts, role grants)
- Bulk data extraction via API
- Credential misuse (service account abuse)
- Configuration tampering (property changes, ACL modifications)
ServiceNow Logging Architecture
| Log Source | What It Captures | Default Retention | Security Use |
|---|---|---|---|
sys_audit |
Field-level changes on audited tables | 180 days | Detect unauthorized modifications |
syslog |
Application logs, errors, info messages | 30 days | Detect script errors, security events |
syslog_transaction |
HTTP requests with user, URL, duration | 7 days | Detect API abuse, bulk extraction |
sys_security_acl_log |
ACL evaluation results (when debug enabled) | Not enabled by default | Debug ACL issues |
sysevent |
System events triggered by platform | 30 days | Track async operations |
sys_user_session |
Active user sessions | Session lifetime | Track concurrent access |
login_log / syslog |
Login attempts (success and failure) | 30 days | Detect brute force, credential stuffing |
Critical Audit Properties
Beyond table-level auditing, these system properties control fundamental audit behavior:
| Property | Purpose | Secure Value | Default | Impact if Misconfigured |
|---|---|---|---|---|
glide.sys.audit_inserts |
Log INSERT operations in sys_audit | true | false | New admin accounts, role grants, and record creations go unlogged |
glide.security.sandbox_no_logging |
Suppress sandbox violation logging | false | true | Script sandbox bypass attempts are hidden from syslog |
glide.identity.security.audit.enabled |
Log identity/security events | true | true | Identity changes (MFA, SSO) not tracked |
glide.sys.activity_using_audit_direct |
Write activity directly to audit | false | false | Performance impact if enabled, but useful for sensitive tables |
Instance-validated finding (Zurich Patch 4): On the tested instance,
glide.sys.audit_inserts = false(default) andglide.security.sandbox_no_logging = true(default). This means: (1) when an attacker grants themselves the admin role by inserting asys_user_has_rolerecord, no audit entry is created for the INSERT — only subsequent UPDATEs would be logged; (2) any script that attempts to break out of the Rhino sandbox produces no syslog entry, allowing an attacker to probe sandbox bypasses silently.
The Problem
Most organizations:
- Don't audit the right tables (HR, CMDB, credentials)
- Set retention too short for incident investigation (7-30 days)
- Don't monitor logs for security anomalies
- Don't alert on high-risk events (new admin, bulk API access)
- Never review transaction logs to detect data exfiltration
- Leave
glide.sys.audit_inserts = false— so record creation events are invisible - Leave
glide.security.sandbox_no_logging = true— so sandbox violation attempts are hidden
Why This Is Dangerous
Attack Scenario: Undetected Data Exfiltration
Precondition: Transaction logging retention is 7 days (default). No anomaly detection on API usage.
Attack chain:
- Compromise: Attacker obtains valid credentials (phishing, password reuse)
- Low-and-slow extraction: Attacker extracts 1,000 records per day via Table API over 2 weeks
- No alert fires: No anomaly detection on API volume per user
- Evidence destroyed: By day 8, the first week's transaction logs are deleted
- Discovery: Weeks later, extracted data appears on dark web
- Investigation fails: Transaction logs are gone — cannot determine scope of breach
Impact: Without logging, a breach has no forensic trail. Regulatory notification (NIS2: 24h, GDPR: 72h) becomes impossible to scope.
Attack Scenario: Privilege Escalation Without Detection
Precondition: sys_user_has_role table is not audited. No alert on admin role grants.
Attack chain:
- Compromised admin account grants
adminrole to attacker's account - Attacker accesses instance with admin privileges
- No audit record of when the role was granted or by whom
- When discovered, forensic timeline cannot be established
How to Detect
Instance Security Center Coverage
Instance Security Center (SSC) has limited overlap with Insufficient Audit Logging and Security Event Detection. SSC focuses on platform hardening properties (CSRF, cookies, session, HSP) and does not audit the audit logging configuration itself — i.e., whether specific tables are audited or whether critical audit system properties are set.
What SSC hardening checks may cover (partial overlap):
- General platform security posture — SSC's overall score reflects whether basic hardening is in place, but audit logging configuration is not a scored dimension
- Some SSC checks may indirectly depend on audit logging being enabled (e.g., login monitoring requires login events to be captured)
What SSC does NOT cover (gaps filled by the script below):
- Per-table audit enablement — SSC does not check whether
sys_user_has_role,sys_security_acl,discovery_credentials, or any other security-critical table has auditing enabled. This is the core risk Insufficient Audit Logging and Security Event Detection addresses (→ Detection Script) glide.sys.audit_inserts— the single most critical audit property (enables INSERT logging) is not in SSC hardening checks. Without it, record creation events are invisible insys_auditglide.security.sandbox_no_logging— suppresses sandbox violation logging; not audited by SSC- Log retention periods — SSC does not evaluate whether transaction log, audit, or syslog retention meets regulatory minimums (NIS2/DORA require forensic capability; 7-day default transaction log retention is insufficient)
- Audit completeness assessment — SSC does not provide a gap analysis of which security-critical tables lack auditing
Recommendation: SSC cannot substitute for Insufficient Audit Logging and Security Event Detection detection. Run the script below to identify audit logging gaps, then use SSC scan results alongside as complementary evidence for NIS2 Art.21§2(f) effectiveness assessment (see Security Center Configuration and OOTB Security Checks).
Detection Script
/*
* MON-001 Detection Script
* Checks audit logging configuration for security-critical tables
*
* Run as: Background script with admin role
* Impact: Read-only, safe for production
*
* Security Center gap: SSC does not audit per-table audit configuration,
* INSERT logging (glide.sys.audit_inserts), sandbox violation logging,
* or log retention periods. This script is the only way to detect
* audit logging gaps on security-critical tables.
*/
// Tables that MUST be audited for security
var criticalTables = [
{ table: 'sys_user', reason: 'User account changes' },
{ table: 'sys_user_has_role', reason: 'Role assignments' },
{ table: 'sys_user_group_member', reason: 'Group membership changes' },
{ table: 'sys_security_acl', reason: 'ACL modifications' },
{ table: 'sys_properties', reason: 'System property changes' },
{ table: 'sys_script', reason: 'Business rule changes' },
{ table: 'sys_script_include', reason: 'Script include changes' },
{ table: 'sysauto_script', reason: 'Scheduled job changes' },
{ table: 'hr_case', reason: 'HR case access/changes' },
{ table: 'cmdb_ci', reason: 'CMDB modifications' },
{ table: 'discovery_credentials', reason: 'Discovery credential changes' },
{ table: 'sys_update_set', reason: 'Update set imports' }
];
gs.info('=== MON-001: AUDIT LOGGING CONFIGURATION CHECK ===');
var audited = 0;
var notAudited = 0;
for (var i = 0; i < criticalTables.length; i++) {
var entry = criticalTables[i];
var dict = new GlideRecord('sys_dictionary');
dict.addQuery('name', entry.table);
dict.addQuery('element', '');
dict.query();
var isAudited = false;
if (dict.next()) {
isAudited = dict.getValue('audit') === 'true' ||
dict.getValue('audit') === '1';
}
if (isAudited) {
audited++;
gs.info('[OK] ' + entry.table + ' — audited (' + entry.reason + ')');
} else {
notAudited++;
gs.info('[FAIL] ' + entry.table + ' — NOT audited (' + entry.reason + ')');
}
}
gs.info('');
gs.info('Audited: ' + audited + ' / ' + criticalTables.length);
gs.info('Not audited: ' + notAudited);
gs.info('');
// Audit retention is configured per table in the Audit Management Console
// (security_admin role required). There is no global sys_property for it, so
// nothing here can read it; the review below is manual by necessity.
gs.info('--- AUDIT RETENTION (manual review required) ---');
gs.info(' Navigate to All > Audit Management Console.');
gs.info(' For each security-critical audited table, open Retention tab');
gs.info(' and confirm Automatically Purge Audit Records toggle is set');
gs.info(' with Duration meeting compliance minimum.');
gs.info(' Reference: setup-audit-retention.md (canonical procedure).');
// Transaction log / syslog retention is governed by Table Rotation, not by a
// sys_property. High-volume log tables are managed by the Database Rotation
// plugin (com.snc.db.rotation) with rotation rules in
// All > System Definition > Table Rotations.
gs.info('--- TRANSACTION LOG / SYSLOG RETENTION (manual review required) ---');
gs.info(' Navigate to All > System Definition > Table Rotations.');
gs.info(' For syslog_transaction and syslog, confirm a rotation rule');
gs.info(' exists. Effective retention ≈ Rotations × Duration. Recommend');
gs.info(' ≥ 90 days for incident-investigation capability.');
gs.info(' Reference: c_TableRotation.md');
gs.info('');
// Check critical audit system properties
var auditProps = [
{ prop: 'glide.sys.audit_inserts', expected: 'true', severity: 'CRITICAL',
desc: 'INSERT operations not logged — new records (admin grants, backdoor accounts) invisible' },
{ prop: 'glide.security.sandbox_no_logging', expected: 'false', severity: 'HIGH',
desc: 'Sandbox violations suppressed — attacker probing sandbox bypasses silently' },
{ prop: 'glide.identity.security.audit.enabled', expected: 'true', severity: 'HIGH',
desc: 'Identity/security events not audited' }
];
gs.info('--- AUDIT SYSTEM PROPERTIES ---');
for (var p = 0; p < auditProps.length; p++) {
var check = auditProps[p];
var value = gs.getProperty(check.prop, 'NOT SET');
var pass = value === check.expected;
gs.info('[' + (pass ? 'OK' : check.severity) + '] ' + check.prop + ' = ' + value +
(pass ? '' : ' (expected: ' + check.expected + ') → ' + check.desc));
if (!pass) notAudited++;
}
gs.info('');
gs.info('RECOMMENDATIONS:');
gs.info('1. Enable auditing on all FAIL tables above');
gs.info('2. Set glide.sys.audit_inserts = true (CRITICAL — enables INSERT logging)');
gs.info('3. Set glide.security.sandbox_no_logging = false (enables sandbox violation logging)');
gs.info('4. Set transaction log retention to 90+ days');
gs.info('5. Set audit retention to 365+ days');
gs.info('6. Create alerts for high-risk events (see MON-002)');
Remediation
Step 1: Enable Auditing on Critical Tables
For each table listed above, enable auditing:
Navigation: System Definition > Tables
Search for table name
Check "Audit" checkbox
Save
Or via script:
/*
* Enable auditing on critical tables
*/
var tablesToAudit = [
'sys_user', 'sys_user_has_role', 'sys_user_group_member',
'sys_security_acl', 'sys_properties', 'sys_script',
'sys_script_include', 'sysauto_script', 'hr_case',
'cmdb_ci', 'discovery_credentials', 'sys_update_set'
];
for (var i = 0; i < tablesToAudit.length; i++) {
var dict = new GlideRecord('sys_dictionary');
dict.addQuery('name', tablesToAudit[i]);
dict.addQuery('element', '');
dict.query();
if (dict.next()) {
dict.setValue('audit', true);
dict.update();
gs.info('Enabled audit on: ' + tablesToAudit[i]);
}
}
Step 1b: Enable Insert Auditing and Sandbox Logging
These are the most commonly missed audit settings. Both are disabled by default:
Set properties:
glide.sys.audit_inserts = true (CRITICAL — log all record INSERTs)
glide.security.sandbox_no_logging = false (log sandbox violations to syslog)
Why
glide.sys.audit_insertsmatters: Without INSERT auditing, the sys_audit table only records UPDATEs and DELETEs. An attacker who creates a newsys_user_has_rolerecord (granting themselves admin) leaves no audit trail — the record simply appears with no forensic evidence of when or by whom it was created. This is validated on a default Zurich instance where this property isfalse.
Step 2: Extend Log Retention
Audit retention on Zurich is configured per-table via the Audit Management Console UI — there is no global sys_property that controls it, and any script that claims to read one is reading nothing.
Procedure (per setup-audit-retention.md):
1. Navigate to All > Audit Management Console (role: security_admin)
2. Select the audited table (e.g., sys_user, sys_user_has_role,
sys_security_acl, oauth_entity, sa_credential)
3. Open the Retention tab
4. Enable "Automatically Purge Audit Records" toggle
5. Set Duration to satisfy compliance minimum (typically 365 days
for SOX/NIS2/DORA; verify your specific framework requirement)
6. Save
For syslog and syslog_transaction retention (per c_TableRotation.md
+ t_ApplyTableRotation.md):
1. Confirm the Database Rotations plugin (com.snc.db.rotation) is
active.
2. Navigate to All > System Definition > Table Rotations (admin).
3. Locate or create a rotation rule for syslog_transaction
(and syslog). Set Rotations × Duration to give ≥ 90 days
effective retention for forensic capability.
4. Engage ServiceNow Customer Service before modifying rotation
rules on out-of-the-box sys_-prefixed tables
(per t_ApplyTableRotation.md guidance).
There is no sys_property for transaction-log or syslog retention.
The mechanism is Table Rotation; a property read here returns nothing.
Step 3: Create Security Event Alerts
See → Missing Security Alerts for High-Risk Events for specific alert configurations.
Post-Remediation Verification
Re-run the detection script above. All critical tables should show as audited. Create a test change (e.g., update a user record) and verify the sys_audit record is created.
Regulatory Impact
NIS2 Mapping
| Article | Requirement | How This Violates It | Evidence After Fix |
|---|---|---|---|
| Art.21§2(a) | Risk analysis and IS security | Cannot assess risk without visibility into security events | Audit logging enabled, retention policy documented |
| Art.21§2(b) | Incident handling | Cannot detect or investigate incidents without logs | Log-based alerting, 365-day retention, forensic capability |
| Art.23§1 | Incident notification (24h) | Cannot scope incident for notification without forensic data | Transaction and audit logs available for investigation |
DORA Mapping
| Article | Requirement | How This Violates It | Evidence After Fix |
|---|---|---|---|
| Art.9§4(a) | Mechanisms to detect ICT anomalous activities | No anomaly detection without baseline logging | Log analysis, anomaly alerts, baseline established |
| Art.17§1 | ICT incident classification | Cannot classify incident severity without impact data from logs | Comprehensive logging enables accurate incident classification |
ISO 27001:2022 Mapping
| Control | Requirement | How This Violates It | Evidence After Fix |
|---|---|---|---|
| A.8.15 | Logging | Security events not logged or retained adequately | Audit enabled on critical tables, retention policy met |
| A.8.16 | Monitoring activities | No monitoring of security-relevant events | Alerts configured, log review process established |
GDPR Mapping
| Article | Requirement | How This Violates It | Impact |
|---|---|---|---|
| Art.30 | Records of processing activities | Cannot demonstrate who accessed personal data without audit logs | Audit logging on PII tables provides access evidence for ROPA |
Expert Notes
Practitioner annotations pending — article content has been technically validated.