← All KB Checks
CRITICALScriptOnlyCheck

MFA Enforcement

nowisor-mfa-enforcement··Source on GitHub →

MFA Enforcement

This page describes the nowisor-mfa-enforcement check from the nowisor Instance Scan Pack v1.0.0. The check audits the glide.authenticate.multifactor system property and produces a finding when the value is not true — including when the property has been removed from sys_properties entirely.

What this finding means

Your ServiceNow instance is not enforcing multi-factor authentication. The system property glide.authenticate.multifactor is either set to a value other than true, or it has been deleted from sys_properties.

When MFA is enforced, every authentication path that supports it — browser login, mobile app, OAuth interactive flows — requires the user to present a second factor (a TOTP code, a push notification approval, an SMS code, or a hardware-token response) in addition to their password. When the property is off, the platform accepts password-only authentication on every path that doesn't have a separately-enforced MFA layer.

The property defaults to "not set" on Zurich Patch 6 — meaning a fresh PDI does not enforce MFA out of the box. Production deployments are expected to set it to true as part of go-live hardening. If the property is "not registered" in your check finding, the instance is operating in the platform default state, which is functional for development but not defensible for production workloads.

A key qualifier: this check audits the platform-level MFA toggle, not whether MFA is enrolled per-user or enforced on REST API paths. Those are companion concerns covered by other checks and configurations.

Why it matters for your compliance

MFA is the most-cited authentication control in modern regulation. Auditors will not let a "no MFA enforced" finding pass without compensating-control evidence that essentially never withstands scrutiny.

NIS2 Article 21§2(j) — identity and access management. NIS2 lists "multi-factor authentication or continuous authentication solutions" as an explicit measure entities must consider. Not implementing it is permitted, but the entity must document why — and the documentation has to survive supervisory scrutiny. "It was hard to enroll users" does not survive.

ISO 27001 A.5.17 — authentication information. A.5.17's control text explicitly addresses authentication information including factors used to verify identity. The 2022 version of the standard moved from advisory MFA language to expectation language. Maintaining an instance without MFA in 2026 is a finding on the very first ISO audit cycle.

DORA Article 9 — ICT risk management framework. DORA Article 9§4(b) covers authentication mechanisms. Financial entities are expected to implement strong authentication for all administrative and privileged access at minimum, and increasingly for all access. Banks, payment institutions, and insurers under DORA fail this control if MFA is not enforced platform-wide.

The check is severity 1 (critical) because the failure mode is the single most-exploited vector against ServiceNow in real-world breaches: an attacker obtains a password (from a credential stuffing list, phishing campaign, or third-party breach) and logs in directly. With MFA, the attacker is stopped at the second factor. Without it, the attacker is in.

The attack path

The attack path is short and well-documented in incident response literature. It's the path that has driven MFA adoption across the industry for the past decade.

Step 1 — Credential acquisition. The attacker obtains a list of leaked passwords from a public breach (Have I Been Pwned, dark-web dumps). The list contains 800 million pairs from various source databases. The attacker filters for @yourcompany.com email patterns. Hundreds of records match.

Step 2 — Targeting. The attacker tries each leaked password against the ServiceNow login page using a slow-rate automated tool. Most accounts fail (the password has been rotated since the breach), but a few succeed — typically the accounts of users who reuse passwords across services and didn't rotate after the breach.

Step 3 — Login. With a working password and no MFA, the attacker logs in. The instance creates a normal authenticated session. The login event is recorded in sys_user_session with the correct user attribution — the only signal that something is wrong is that the source IP is unfamiliar, which most monitoring rules treat as a soft anomaly.

Step 4 — The blast radius. The attacker now has the role-grants of whichever account they compromised. If the account had admin (the worst case, but not uncommon for IT users or developers), the platform is fully compromised. If the account had itil or a more limited role, the attacker pivots — checking what the account can read, what records contain sensitive data, what credentials are stored in change records or knowledge articles.

With MFA enforced, step 3 fails. The attacker has the password but not the second factor. The leaked-password list, no matter how complete, becomes nearly worthless against the instance.

The same path applies via API basic auth on the paths that aren't covered by nowisor-rest-anonymous-access — but that surface area shrinks dramatically once you migrate integrations to OAuth and disable basic auth on all paths that don't need it.

How to fix it

Two steps:

Step 1 — Configure an MFA provider before enabling enforcement. If you enable glide.authenticate.multifactor = true before users have a working MFA setup, they will be locked out of the platform. Configure one of:

Step 2 — Enable enforcement.

glide.authenticate.multifactor = true

Apply via System Properties → glide.authenticate.multifactor. The change takes effect on the next authentication event. Existing sessions remain valid until they expire or the user logs out.

Roll the change out in waves: admins and security_admin role-holders first (smallest group, highest impact), then developers, then end-users. Pair with a brief user-communication so users know to enroll before the change goes live.

Verify the API surface too. If your glide.basicauth.required.* properties are correct (see nowisor-rest-anonymous-access), basic auth still allows password-only access on the API. Migrate integrations to OAuth — OAuth tokens are issued by an authentication flow that itself enforces MFA, so the API access path inherits the MFA decision.

How to verify the fix

Run this Background Script after configuring an MFA provider and enabling enforcement:

/*
 * Verify nowisor-mfa-enforcement
 * Read-only, safe for production.
 * Confirms glide.authenticate.multifactor is enforced + reports enrollment.
 */
(function verifyMfa() {
    var SENTINEL = '__NOT_REGISTERED__';
    var prop = 'glide.authenticate.multifactor';
    var value = gs.getProperty(prop, SENTINEL);

    if (value === SENTINEL) {
        gs.print('[FAIL] ' + prop + ' is NOT REGISTERED in sys_properties.');
        gs.print('       Configure MFA provider, then set the property to "true".');
    } else if (value !== 'true') {
        gs.print('[FAIL] ' + prop + ' = "' + value + '" (expected "true").');
        gs.print('       Update via System Properties.');
    } else {
        gs.print('[PASS] ' + prop + ' = true. MFA enforced at login.');
    }

    // Enrollment snapshot (informational)
    gs.print('');
    gs.print('MFA enrollment snapshot:');
    try {
        var mfaSetup = new GlideRecord('sys_user_mfa_setup');
        mfaSetup.query();
        gs.print('  sys_user_mfa_setup rows: ' + mfaSetup.getRowCount() + ' enrolled users');
    } catch (e) {
        gs.print('  (sys_user_mfa_setup table not accessible in this scope)');
    }

    // Companion: admin role count, for context on enrollment priority
    try {
        var admins = new GlideAggregate('sys_user_has_role');
        admins.addQuery('role.name', 'admin');
        admins.addAggregate('COUNT', 'user');
        admins.query();
        var adminCount = 0;
        while (admins.next()) adminCount++;
        gs.print('  Distinct admin role holders: ' + adminCount);
    } catch (e) {}
})();

Re-run the nowisor scan after applying the fix. The check should no longer produce a finding for this property.

What to do next

MFA closes the credential-stuffing path. Several adjacent paths remain — make sure they don't undo the protection:

For NIS2 and ISO 27001 audits, the nowisor advisor product is being built to package the MFA finding with enrollment statistics, IdP coexistence status, and the local-login bypass check into a single Article 21§2(j) evidence cluster ready for upload to your GRC platform. Get NIS2 evidence with the advisor →