OOB ACL Modifications
This page describes the
nowisor-oob-acl-modificationscheck from the nowisor Instance Scan Pack v1.0.0. The check queriessys_security_aclfor OOB baseline ACLs (sys_package = '', identifying Global-scope OOB rules) that have been modified more than one day after their creation date AND in the last 24 hours. Findings are scoped to the recent change window — the check is designed to catch active drift, not historical state. A single aggregate finding lists sample ACLs (capped at 20) with the operation and name; an overflow count is included if more than 20 ACLs match.
What this finding means
Your instance has out-of-box ServiceNow ACLs that have been modified post-install AND were touched within the last day. The check uses two conditions:
sys_package = ''— identifies ACLs that ship as part of the OOB ServiceNow baseline rather than as part of a customer or third-party application scope. Baseline ACLs are the platform's "factory" access controls; modifications to them mean someone has changed the platform's default security model.sys_updated_on > sys_created_on + 1 dayANDsys_updated_on > beginningOfYesterday()— combines the "this ACL has been touched after seeding" check with a recent-activity filter. The recency filter is intentional: it scopes the finding to active operational drift, not to historical changes that have been in place for years.
The narrow time window is a design choice worth explaining. On a stable production instance, OOB ACLs should not be modified frequently — once they're customized to your security model, they should stay customized. A finding here means there has been recent activity on the baseline ACL surface, which warrants a look at whether the activity is authorized.
A clean instance produces zero findings. A finding indicates either: an upgrade reapplied baseline ACL definitions (legitimate, but worth confirming the upgrade-skipped-changes were captured); a developer made a quick "I'll just adjust this ACL" change without going through change control (operational drift); or an attacker is currently modifying baseline ACLs as part of an active intrusion (the lowest-probability but highest-impact case the recency window targets).
Why it matters for your compliance
Baseline ACL integrity is one of the canonical change-management controls.
NIS2 Article 21§2(a) — risk analysis and information system security policies. Article 21§2(a) covers the entity's documented security policies and the systems that enforce them. The OOB baseline ACL set is the platform's default enforcement of the entity's documented policy; unauthorized modifications break that enforcement without changing the documented policy. NIS2 supervisors look for change-management evidence specifically around access controls.
ISO 27001 A.8.3 — information access restriction. A.8.3 requires access restrictions to be implemented according to policy. The baseline ACLs are the implementation; modifications to them are policy changes by deployment. The control expects the modifications to be documented, approved, and tracked. The check surfaces the modifications so the documentation step can catch up.
The check is severity 2 (high), not critical, because the failure mode is detection-of-drift rather than detection-of-active-compromise. A finding warrants investigation but is not on its own evidence of a breach. The investigation outcome — "expected upgrade behavior" vs "unexpected modification" vs "active tampering" — determines the response.
The attack path
The attack path is an insider or compromised-account modifying baseline ACLs to weaken the access control model without leaving an obvious trace.
Step 1 — The attacker has admin or security_admin access. This is required to modify sys_security_acl records. The access may have been obtained through a compromised account (the upstream attack), through an insider with legitimate access who is now acting maliciously, or through a credential leak.
Step 2 — Identify the target ACL. The attacker chooses an OOB ACL to modify. Common targets: ACLs that protect sensitive tables (hr_case, sn_hr_core_case, sys_credentials, sys_user.user_password), ACLs that protect security configuration (sys_security_acl itself, sys_user_has_role), or ACLs that protect audit trails (sys_audit, sys_audit_delete).
Step 3 — Weaken or replace the rule. The attacker modifies the ACL — perhaps changing the required role from hr_admin to itil (broadening access), perhaps changing the script condition from a strict check to one that always returns true, perhaps adding a "Roles" entry that includes their own user-id. The change is captured in sys_update_xml and sys_audit (assuming audit is configured for ACL changes, which it should be), but a defender who isn't actively watching the audit trail may not catch it.
Step 4 — Exfiltrate or escalate. With the weakened ACL in place, the attacker performs the action the original ACL would have blocked: queries the sensitive table, modifies the privilege grants, deletes the audit trail. The action itself appears in the audit log, but the ACL change that enabled it is what the defender needs to catch.
Step 5 — Restore (optional). A sophisticated attacker reverts the ACL after the operation to remove the most visible trace. The Updates related list on the ACL still shows the modification history, but a casual review might miss the brief weakening window.
The check's recency window is designed for exactly this attack pattern. It surfaces ACL modifications happening NOW — not the historical record of changes from years ago. The window is the trade-off: it catches active operations and reduces noise from old changes that have already been investigated.
How to fix it
Investigation, not configuration change. For each flagged ACL:
Step 1 — Open the ACL record. Navigate to the sys_security_acl row directly from the finding's evidence (the sys_id is included). Review:
- The operation (read, write, create, delete, execute)
- The target table or field
- The required role(s) and condition script
- The
Updatesrelated list — who modified the record, when, and what they changed
Step 2 — Compare to baseline. Cross-reference the current state to the upgrade history. Open System Update Sets → Upgrade History and search for entries related to sys_security_acl_<sys_id>. If the upgrade history shows the entry was marked as "Skipped" (because the platform detected a local modification), the change is intentional and you have the customization point documented.
Step 3 — Decide on each modification:
- Intentional hardening — the customer's security team modified the ACL to be more restrictive. This is correct in principle, but the modification should be moved into a custom application scope rather than left on the global baseline ACL. Moving the change to a scope ensures that future ServiceNow upgrades cannot silently revert the hardening.
- Unintentional drift — someone modified the ACL by mistake. Revert via Upgrade History (which preserves the baseline definition) or by manually restoring the original logic from a freshly-patched comparison instance.
- Suspicious modification — the change was made by an account that shouldn't have been touching ACLs, or the change weakens the rule in a way that doesn't fit any business case. Escalate to incident response. Preserve the change history before reverting; the audit trail is forensic evidence.
Step 4 — Implement change control going forward. ACL modifications should be tracked via the entity's change-management process. Each modification should be linked to a change request that documents the business case and approval. The change record's link to the ACL provides the documentation that audit will ask for during compliance reviews.
How to verify the fix
Run the audit query directly to confirm the finding's data:
/*
* Verify nowisor-oob-acl-modifications
* Read-only, safe for production.
* Lists baseline ACLs modified in the last 24 hours.
*/
(function auditOobAcls() {
var gr = new GlideRecord('sys_security_acl');
gr.addQuery('sys_package', '');
gr.addQuery('sys_updated_on', '>', 'javascript:gs.beginningOfYesterday()');
gr.orderByDesc('sys_updated_on');
gr.query();
var count = 0;
while (gr.next()) {
var createdGdt = new GlideDateTime(gr.getValue('sys_created_on'));
var updatedGdt = new GlideDateTime(gr.getValue('sys_updated_on'));
var deltaMs = updatedGdt.getNumericValue() - createdGdt.getNumericValue();
if (deltaMs <= 86400000) continue; // < 1 day, skip
count++;
gs.print(
' ' +
(gr.getValue('name') || gr.getValue('sys_id')) +
' (' + gr.getValue('operation') + ', updated by ' +
gr.getValue('sys_updated_by') + ')'
);
}
if (count === 0) {
gs.print('[PASS] No OOB ACL modifications in the last day.');
} else {
gs.print('[FAIL] ' + count + ' OOB ACL(s) modified recently. Review each.');
}
})();
The expected state on a stable instance is zero. A finding immediately after an upgrade is expected (the upgrade may have touched baseline ACLs); a finding outside of an upgrade window warrants investigation.
What to do next
OOB ACL modifications interact with the privilege-cluster findings:
nowisor-cross-scope-privilege-grants— scope privileges granted to apps that interact with ACL-protected data. A weakened ACL + a cross-scope grant compounds the exposure.nowisor-admin-role-concentration/nowisor-elevated-role-assignments— modifying ACLs requiresadminorsecurity_admin. A high admin population means more candidates for either insider misuse or compromise-driven modification.
For organizations under NIS2 supervisory review, the nowisor advisor product is being built to correlate the OOB ACL modification finding with the change-request tracking system — surfacing which modifications have linked CRs (legitimate) and which don't (operational drift or worse). Audit your baseline ACL drift →