← All security articles
CRITICALWashington DC, Xanadu, Yokohama, Zurich

BodySnatcher: Virtual Agent Impersonation (CVE-2025-12420)

Domain 7: Architecture & Threat Modeling·

BodySnatcher lets an unauthenticated attacker impersonate any user on your instance, administrators included, knowing only that person's email address. The root cause was a client secret hardcoded identically into every ServiceNow deployment worldwide, so nothing you configured made you more or less exposed than anyone else. If your instance ran Now Assist AI Agents or the Virtual Agent API before the fix landed, treat impersonation as possible and review who used them.

What This Is

In October 2025, Aaron Costello, Chief of SaaS Security Research at AppOmni, discovered a critical authentication bypass vulnerability in ServiceNow's Now Assist AI Agents and Virtual Agent API. The flaw — dubbed "BodySnatcher" — allows an unauthenticated attacker to impersonate any user on a ServiceNow instance, including administrators, by exploiting a hardcoded client secret that is identical across every ServiceNow deployment worldwide. The attacker needs only the target's email address and can bypass MFA and SSO entirely.

Field Detail
CVE CVE-2025-12420
Name BodySnatcher
CVSS 9.3 (Critical)
Type Authentication bypass via hardcoded credential + identity impersonation
Discovered by Aaron Costello, Chief of SaaS Security Research, AppOmni
Discovery date October 2025
Patch date October 30, 2025
Public disclosure January 13, 2026 (AppOmni blog, Canadian Centre for Cyber Security advisory AV26-022)

Affected components and versions:

Plugin Scope Vulnerable Versions Patched Versions
Now Assist AI Agents sn_aia < 5.1.18, < 5.2.19 5.1.18+, 5.2.19+
Virtual Agent API sn_va_as_service < 3.15.2, < 4.0.4 3.15.2+, 4.0.4+

Hosted instances were patched by ServiceNow on October 30, 2025. Non-hosted (self-managed) instances must verify plugin versions manually and apply updates if they have not been auto-upgraded.

Technical Background: The Hardcoded Secret

Every ServiceNow instance worldwide ships with AI Agent channel providers that contain an identical static client secret. This secret is not unique per instance — it is a platform-wide constant baked into the sn_aia and sn_va_as_service plugins. An attacker who extracts or identifies this secret from any single ServiceNow instance can use it against every other instance on the planet.

The Virtual Agent API's account-linking logic trusts a simple email address claim as an identity assertion. When an API consumer authenticates with the hardcoded client secret and provides an email address, the platform binds the session to the user account matching that email — no password, no MFA challenge, no SSO redirect. The system treats the channel provider's client secret as sufficient proof that the caller is authorized to act on behalf of the claimed user.

This design violates fundamental identity security principles: a shared secret is not an identity proof, and an email address is not an authentication factor. The combination of these two flaws creates a universal authentication bypass.

Disclosure Timeline

Why This Is Dangerous

Attack Scenario: Full Identity Takeover via Virtual Agent Channel

Precondition: ServiceNow instance running vulnerable versions of sn_aia (< 5.1.18 / < 5.2.19) or sn_va_as_service (< 3.15.2 / < 4.0.4) with any Virtual Agent channel provider active. The attacker needs no prior access to the target instance — only knowledge of the hardcoded secret and a target user's email address.

Attack chain:

  1. Secret acquisition: An attacker extracts the hardcoded platform-wide client secret from any ServiceNow instance they have access to (including free developer instances, trial instances, or any instance where they hold even the lowest-privilege account). Because the secret is identical across all instances, extracting it once grants the ability to authenticate to every vulnerable instance globally.

  2. Channel authentication: The attacker authenticates to the target instance's Virtual Agent API channel endpoint using the hardcoded client secret. The platform accepts this as a legitimate channel provider connection.

  3. Identity claim: The attacker provides the target user's email address as the identity claim in the account-linking flow. The email address is the only input needed — no password, no token, no second factor.

  4. Account binding: The Virtual Agent API's account-linking logic trusts the email address without verification. The platform binds the attacker's session to the target user's account. MFA and SSO are completely bypassed because the authentication occurs at the channel provider level, which sits outside the normal user authentication flow.

  5. Full session impersonation: The attacker now operates as the target user with their complete set of roles and permissions. Every action the attacker takes is attributed to the victim in audit logs.

  6. AI agent execution: The attacker can invoke Now Assist AI Agents that execute with the impersonated user's privileges. If the target is an administrator, these agentic AI workflows can:

    • Create new user accounts with admin roles (sys_user, sys_user_has_role)
    • Modify ACL rules and security controls (sys_security_acl)
    • Exfiltrate data from any table the admin can access
    • Modify system properties (sys_properties)
    • Execute server-side scripts via AI agent actions
    • Disable audit logging or modify security baselines
    • Install or modify applications and plugins
  7. Persistence: An attacker impersonating an admin can create backdoor accounts, grant elevated roles, install custom applications with hidden scripts, or modify business rules to maintain access even after the vulnerability is patched.

Impact Analysis

Factor Assessment
Authentication required None — unauthenticated attack
Information needed Target user's email address only
MFA bypass Complete — channel authentication sits outside MFA flow
SSO bypass Complete — channel authentication sits outside SSO flow
Scope Any user on any vulnerable instance worldwide
Stealth High — actions logged under victim's identity
Blast radius Admin impersonation = full instance compromise

As Aaron Costello stated: "Attackers could have effectively 'remote controlled' an organization's AI, weaponizing the tools meant to simplify the enterprise."

The critical differentiator from Jelly Template Injection RCE Chain (CVE-2024-4879, CVE-2024-5178, CVE-2024-5217) (Jelly Template Injection) is the attack surface: Jelly Template Injection RCE Chain (CVE-2024-4879, CVE-2024-5178, CVE-2024-5217) required network access to a MID Server, while BodySnatcher targets cloud-hosted API endpoints that are internet-facing by design. Any ServiceNow instance with Virtual Agent channels active was exploitable from anywhere on the internet with nothing more than an email address.

How to Detect

Check Plugin Versions

/*
 * CVE-002 Patch Verification Script
 * Checks sn_aia and sn_va_as_service plugin versions
 *
 * Run as: Background script with admin role
 * Impact: Read-only, safe for production
 * Versions: Washington DC+
 */

gs.info('=== CVE-002: BODYSNATCHER PATCH VERIFICATION ===');
gs.info('');

// Check Now Assist AI Agents (sn_aia)
var aiaApp = new GlideRecord('sys_store_app');
aiaApp.addQuery('scope', 'sn_aia');
aiaApp.query();

if (aiaApp.next()) {
    var aiaVersion = aiaApp.getValue('version');
    gs.info('Now Assist AI Agents (sn_aia): ' + aiaVersion);

    // Parse major.minor.patch
    var aiaParts = aiaVersion.split('.');
    var aiaMajor = parseInt(aiaParts[0], 10);
    var aiaMinor = parseInt(aiaParts[1], 10);
    var aiaPatch = parseInt(aiaParts[2], 10);

    if (aiaMajor === 5 && aiaMinor === 1 && aiaPatch < 18) {
        gs.info('  STATUS: VULNERABLE (requires 5.1.18+)');
    } else if (aiaMajor === 5 && aiaMinor === 2 && aiaPatch < 19) {
        gs.info('  STATUS: VULNERABLE (requires 5.2.19+)');
    } else if (aiaMajor >= 5) {
        gs.info('  STATUS: PATCHED');
    } else {
        gs.info('  STATUS: UNKNOWN version line — verify manually');
    }
} else {
    gs.info('Now Assist AI Agents (sn_aia): NOT INSTALLED');
    gs.info('  STATUS: Not affected (plugin not present)');
}

gs.info('');

// Check Virtual Agent API (sn_va_as_service)
var vaApp = new GlideRecord('sys_store_app');
vaApp.addQuery('scope', 'sn_va_as_service');
vaApp.query();

if (vaApp.next()) {
    var vaVersion = vaApp.getValue('version');
    gs.info('Virtual Agent API (sn_va_as_service): ' + vaVersion);

    var vaParts = vaVersion.split('.');
    var vaMajor = parseInt(vaParts[0], 10);
    var vaMinor = parseInt(vaParts[1], 10);
    var vaPatch = parseInt(vaParts[2], 10);

    if (vaMajor === 3 && (vaMinor < 15 || (vaMinor === 15 && vaPatch < 2))) {
        gs.info('  STATUS: VULNERABLE (requires 3.15.2+)');
    } else if (vaMajor === 4 && vaMinor === 0 && vaPatch < 4) {
        gs.info('  STATUS: VULNERABLE (requires 4.0.4+)');
    } else if (vaMajor >= 4 || (vaMajor === 3 && vaMinor >= 15 && vaPatch >= 2)) {
        gs.info('  STATUS: PATCHED');
    } else {
        gs.info('  STATUS: UNKNOWN version line — verify manually');
    }
} else {
    gs.info('Virtual Agent API (sn_va_as_service): NOT INSTALLED');
    gs.info('  STATUS: Not affected (plugin not present)');
}

Check Active Virtual Agent Channel Providers

/*
 * Enumerate active Virtual Agent channel providers
 * Active channels represent the exploitable attack surface
 *
 * Run as: Background script with admin role
 * Impact: Read-only, safe for production
 * Versions: Washington DC+
 */

gs.info('=== CVE-002: VIRTUAL AGENT CHANNEL AUDIT ===');
gs.info('');

// Check for active channel provider configurations
var channel = new GlideRecord('sys_cs_channel_provider');
channel.query();

if (channel.getRowCount() > 0) {
    gs.info('Active channel providers found: ' + channel.getRowCount());
    gs.info('');
    while (channel.next()) {
        gs.info('Channel: ' + channel.getValue('name') +
            ' | Active: ' + channel.getValue('active') +
            ' | Type: ' + channel.getValue('type') +
            ' | Scope: ' + channel.getValue('sys_scope') +
            ' | Updated: ' + channel.getValue('sys_updated_on'));
    }
    gs.info('');
    gs.info('WARNING: Each active channel provider was a potential entry point for BodySnatcher.');
    gs.info('If any channel was active before October 30, 2025, investigate for exploitation.');
} else {
    gs.info('No channel providers found. Virtual Agent channels may not be configured.');
    gs.info('Check sys_cs_channel manually if Virtual Agent is in use.');
}

gs.info('');

// Check for AI Agent configurations
var aiAgent = new GlideRecord('sys_cb_ai_agent');
if (aiAgent.isValid()) {
    aiAgent.addQuery('active', true);
    aiAgent.query();
    gs.info('Active AI Agents: ' + aiAgent.getRowCount());
    while (aiAgent.next()) {
        gs.info('  Agent: ' + aiAgent.getValue('name') +
            ' | Active: ' + aiAgent.getValue('active') +
            ' | Scope: ' + aiAgent.getValue('sys_scope'));
    }
} else {
    gs.info('AI Agent table (sys_cb_ai_agent) not found — Now Assist AI Agents may not be installed.');
}

Check for Indicators of Exploitation

/*
 * Search for indicators of BodySnatcher exploitation
 * Focus period: Before October 30, 2025 (patch date)
 *
 * Run as: Background script with admin role
 * Impact: Read-only, safe for production
 * Versions: Washington DC+
 */

gs.info('=== CVE-002: EXPLOITATION INDICATOR CHECK ===');
gs.info('Focus: September 1, 2025 — October 30, 2025 (pre-patch window)');
gs.info('');

// 1. Check for admin accounts created during vulnerability window
gs.info('--- Admin Role Grants During Vulnerability Window ---');
var adminGrants = new GlideRecord('sys_user_has_role');
adminGrants.addQuery('sys_created_on', '>=', '2025-09-01');
adminGrants.addQuery('sys_created_on', '<=', '2025-10-31');
adminGrants.addQuery('role.name', 'admin');
adminGrants.query();

if (adminGrants.getRowCount() > 0) {
    gs.info('WARNING: ' + adminGrants.getRowCount() + ' admin role assignments found');
    while (adminGrants.next()) {
        gs.info('  User: ' + adminGrants.getDisplayValue('user') +
            ' | Granted: ' + adminGrants.getValue('sys_created_on') +
            ' | Granted by: ' + adminGrants.getDisplayValue('sys_created_by'));
    }
} else {
    gs.info('No admin role grants during vulnerability window.');
}

gs.info('');

// 2. Check for new user accounts created during window
gs.info('--- New User Accounts During Vulnerability Window ---');
var newUsers = new GlideRecord('sys_user');
newUsers.addQuery('sys_created_on', '>=', '2025-09-01');
newUsers.addQuery('sys_created_on', '<=', '2025-10-31');
newUsers.orderByDesc('sys_created_on');
newUsers.setLimit(50);
newUsers.query();

gs.info('New accounts created: ' + newUsers.getRowCount());
while (newUsers.next()) {
    gs.info('  User: ' + newUsers.getValue('user_name') +
        ' | Email: ' + newUsers.getValue('email') +
        ' | Created: ' + newUsers.getValue('sys_created_on') +
        ' | Created by: ' + newUsers.getValue('sys_created_by') +
        ' | Active: ' + newUsers.getValue('active'));
}

gs.info('');

// 3. Check Virtual Agent conversation logs for anomalies
gs.info('--- Virtual Agent Conversations During Window ---');
var vaLog = new GlideRecord('sys_cs_conversation');
if (vaLog.isValid()) {
    vaLog.addQuery('sys_created_on', '>=', '2025-09-01');
    vaLog.addQuery('sys_created_on', '<=', '2025-10-31');
    vaLog.orderByDesc('sys_created_on');
    vaLog.setLimit(50);
    vaLog.query();

    gs.info('Virtual Agent conversations found: ' + vaLog.getRowCount());
    while (vaLog.next()) {
        gs.info('  User: ' + vaLog.getDisplayValue('opened_for') +
            ' | Channel: ' + vaLog.getValue('channel') +
            ' | Created: ' + vaLog.getValue('sys_created_on') +
            ' | State: ' + vaLog.getValue('state'));
    }
    gs.info('');
    gs.info('INVESTIGATE: Look for conversations from admin accounts via non-standard channels.');
    gs.info('An attacker using BodySnatcher would appear as the impersonated user.');
} else {
    gs.info('Conversation table not accessible — check sys_cs_conversation manually.');
}

gs.info('');

// 4. Check for ACL or security control modifications during window
gs.info('--- Security Control Modifications During Window ---');
var aclChanges = new GlideRecord('sys_security_acl');
aclChanges.addQuery('sys_updated_on', '>=', '2025-09-01');
aclChanges.addQuery('sys_updated_on', '<=', '2025-10-31');
aclChanges.query();

gs.info('ACL modifications during window: ' + aclChanges.getRowCount());
if (aclChanges.getRowCount() > 0) {
    while (aclChanges.next()) {
        gs.info('  ACL: ' + aclChanges.getValue('name') +
            ' | Table: ' + aclChanges.getValue('name') +
            ' | Operation: ' + aclChanges.getValue('operation') +
            ' | Updated by: ' + aclChanges.getValue('sys_updated_by') +
            ' | Updated: ' + aclChanges.getValue('sys_updated_on'));
    }
}

gs.info('');
gs.info('MANUAL CHECKS REQUIRED:');
gs.info('1. Review sys_audit for actions attributed to admin users that occurred via Virtual Agent channels');
gs.info('2. Check syslog for Virtual Agent API authentication events from unexpected sources');
gs.info('3. Review sys_user_session for sessions initiated via channel provider authentication');
gs.info('4. Check sys_properties for modifications to security-related properties during the window');
gs.info('5. Look for custom applications or business rules installed during the window');

Remediation

Step 1: Verify Patch Versions (Immediate)

  1. Run the patch verification script above to check sn_aia and sn_va_as_service versions
  2. Hosted instances: ServiceNow patched hosted instances on October 30, 2025. Confirm by verifying plugin versions in System Applications > All Available Applications > Installed
  3. Non-hosted instances: Update plugins immediately:
    • sn_aia must be >= 5.1.18 (5.1.x line) or >= 5.2.19 (5.2.x line)
    • sn_va_as_service must be >= 3.15.2 (3.x line) or >= 4.0.4 (4.x line)
  4. If either plugin is below the patched version, treat the instance as actively compromised until investigation proves otherwise

Step 2: Audit for Exploitation Indicators (Within 48 Hours)

An attacker who exploited BodySnatcher would have operated under the identity of the impersonated user. Standard audit logs will show actions attributed to the victim, not the attacker. Focus on behavioral anomalies:

1. Admin account creation:
   - Query sys_user_has_role for admin grants between Sept-Oct 2025
   - Cross-reference with change management records — any admin grants without an approved change request are suspicious

2. Virtual Agent activity from admin accounts:
   - Query sys_cs_conversation for conversations opened by admin users
   - Admins rarely interact with Virtual Agent directly — any such conversations are anomalous

3. Unusual session patterns:
   - Check sys_user_session for admin sessions that lack corresponding SSO/MFA authentication events
   - An attacker using BodySnatcher would create sessions that bypass the normal authentication flow

4. Security control modifications:
   - Query sys_security_acl for ACL changes during the window
   - Query sys_properties for changes to security properties (glide.security.*, glide.basicauth.*, etc.)
   - Query sys_script for new or modified business rules, especially those running as system

5. Data exfiltration signals:
   - Review sys_audit for bulk READ operations on sys_user, discovery_credentials, sys_properties
   - Check outbound REST/SOAP message logs for unexpected data transfers

Step 3: Rotate Credentials (If Exploitation Suspected)

If any exploitation indicators are found, or if the instance was running vulnerable versions with active Virtual Agent channels before October 30, 2025:

1. Rotate all credentials that may have been accessed:
   - All ServiceNow user passwords (force password reset for all users)
   - All integration credentials stored in sys_connection or connection_alias
   - All OAuth tokens and client secrets (sys_oauth_entity, oauth_credential)
   - All discovery credentials
   - All import set / data source credentials
   - API keys stored in system properties

2. Revoke all active sessions:
   - Truncate sys_user_session to force re-authentication
   - Invalidate all active OAuth tokens

3. If admin impersonation is suspected:
   - Audit all user accounts created during the window and disable any that cannot be verified
   - Review all role assignments made during the window
   - Check for installed applications, plugins, or update sets that were not approved
   - Review scheduled jobs for persistence mechanisms

Step 4: Review Virtual Agent Channel Configurations (Ongoing)

1. Inventory all channel providers:
   - Navigate to Virtual Agent > Channel Providers
   - Document all active channels and their authentication configurations
   - Disable any channels that are not actively used

2. Verify patched behavior:
   - After patching, the client secret is no longer static/shared
   - Verify that account-linking now requires proper identity verification
   - Test by attempting to authenticate with the old hardcoded secret — it should fail

3. Implement monitoring:
   - Alert on new channel provider configurations
   - Alert on changes to Virtual Agent API settings
   - Monitor for authentication attempts using invalid or revoked client secrets

4. Network controls:
   - Restrict Virtual Agent API endpoints to known, trusted IP ranges where possible
   - Implement rate limiting on channel authentication endpoints
   - Enable enhanced logging for all Virtual Agent API interactions

Regulatory Impact

NIS2 Mapping

Article Requirement How This CVE Triggers It Required Actions
Art.21§2(a) Risk analysis and IS security policies A hardcoded, platform-wide secret in a critical authentication path represents a systemic risk that must be identified and mitigated Document vulnerability in risk register, verify patch, assess residual risk from pre-patch exposure window
Art.21§2(d) Supply chain security ServiceNow as a supply chain component introduced a universal authentication bypass affecting all downstream organizations Assess supply chain impact, verify vendor patch, document in third-party risk assessment
Art.21§2(i) Human resources security, access control policies, asset management An attacker can impersonate any user including admins, completely defeating access control policies and identity governance Audit all access during vulnerability window, verify no unauthorized identity changes persisted

DORA Mapping

Article Requirement How This CVE Triggers It Required Actions
Art.9§1 ICT risk management framework Critical vulnerability in AI/automation platform must be managed within ICT risk framework; hardcoded secrets represent an unacceptable architectural risk Document in ICT risk register, assess impact on critical financial functions, verify remediation
Art.9§2 Identification of ICT risks Must identify whether the vulnerability was exploited and assess impact on financial operations and data integrity Conduct exploitation indicator analysis, document findings, assess data integrity impact

ISO 27001:2022 Mapping

Control Requirement Relevance Evidence
A.8.8 Management of technical vulnerabilities Timely identification and remediation of a critical authentication bypass in a core platform Patch verification records, vulnerability window assessment, remediation timeline documentation
A.8.9 Configuration management Hardcoded secrets and default channel configurations must be identified and remediated as part of configuration management Channel provider inventory, post-patch configuration review, default credential elimination
A.5.17 Authentication information The hardcoded client secret and email-only identity claim violated authentication information management requirements Evidence of patched authentication flow, credential rotation records, authentication architecture review

GDPR Mapping

Article Requirement How This CVE Triggers It Required Actions
Art.32§1(b) Ability to ensure ongoing confidentiality, integrity, availability, and resilience of processing systems An attacker can impersonate any user and access all personal data processable under that user's permissions, directly undermining confidentiality and integrity If exploitation is confirmed or suspected and personal data may have been accessed, notify supervisory authority within 72 hours (Art.33), assess need for data subject notification (Art.34)

Expert Notes

Practitioner annotations pending — article content has been technically validated.