The MID Server is the most privileged component in the integration architecture: it sits inside your network, holds credentials for the systems it reaches, and runs everything discovery and orchestration ask of it. That makes two hardening questions decisive — what the MID Server's own service account can reach on your network, and whether it validates the instance it talks to rather than trusting any endpoint that answers. A MID Server compromise is a foothold in your network, not just in your instance.
What This Is
The Management, Instrumentation, and Discovery (MID) Server is a Java application deployed inside an organization's network that acts as a secure communication bridge between the ServiceNow cloud instance and on-premise resources. Every discovery scan, orchestration workflow, LDAP import, JDBC connection, and SCCM integration runs through the MID Server. It is the single most privileged component in the ServiceNow integration architecture.
The MID Server communicates bidirectionally:
| Direction | Protocol | Purpose | Security Concern |
|---|---|---|---|
| MID → Instance | HTTPS (outbound) | Polls for work, returns results | Service account credentials stored in config.xml |
| MID → Internal Network | SSH, WMI, SNMP, JDBC, PowerShell | Executes probes against infrastructure | MID Server host has broad network access |
| Instance → MID | Via ECC queue records | Commands encoded as XML payloads | Commands execute with MID service account privileges |
MID Server Configuration Files
| File | Location | Contents | Risk |
|---|---|---|---|
| config.xml | <MID_HOME>/agent/config.xml |
Instance URL, service account username/password, proxy settings, SSL configuration | Plaintext or obfuscated credentials; defines instance trust |
| wrapper-override.conf | <MID_HOME>/agent/wrapper-override.conf |
JVM arguments, memory settings, debug flags, Java security properties | Can disable certificate validation, enable remote debugging |
| keystore files | <MID_HOME>/agent/keystore/ |
TLS certificates for mutual authentication | Missing or self-signed certificates weaken transport security |
| scripts/ | <MID_HOME>/agent/scripts/ |
Custom probe and sensor scripts deployed from instance | Arbitrary code execution capability on the MID host |
MID Server Validation States
| State | Meaning | Security Implication |
|---|---|---|
| Validated | Admin has explicitly approved this MID Server | Trusted to receive and execute commands |
| Not Validated | MID Server connected but not yet approved | Should not receive work; some configurations still allow it |
| Down | MID Server is offline or unresponsive | May indicate compromise, network issue, or unauthorized shutdown |
| Upgrade | MID Server is being auto-upgraded | Temporary vulnerability window during upgrade cycle |
Why the MID Server Is Architecturally Dangerous
MID Server sits at the intersection of two trust boundaries:
CLOUD (ServiceNow Instance)
|
| HTTPS (outbound only from MID)
|
[MID SERVER HOST] — runs as local service account
|
| SSH / WMI / SNMP / JDBC / PowerShell
|
INTERNAL NETWORK (servers, databases, Active Directory, network devices)
Compromise impact:
1. Full access to every system the MID Server can reach on the internal network
2. Credentials for all discovery/orchestration targets (stored in instance, pulled via ECC queue)
3. Ability to inject results back into ServiceNow (modify CMDB, close incidents, alter workflows)
4. Lateral movement pivot point — MID Servers often have broad firewall rules
5. Persistence — MID Server runs as a system service, survives reboots
Why This Is Dangerous
Attack Scenario 1: config.xml Credential Theft and Instance Takeover
Precondition: An attacker gains filesystem access to the MID Server host — via RDP, SSH, local exploit, or supply chain compromise of the host OS. The MID Server service account credentials are stored in config.xml.
Attack chain:
Extract credentials from config.xml:
<!-- Typical config.xml excerpt --> <parameter name="url" value="https://instance.service-now.com"/> <parameter name="mid.instance.username" value="mid.server.prod01"/> <parameter name="mid.instance.password" value="0DPLKaR2bQ8FKSxM..." /> <!-- Encrypted with static key --> <parameter name="mid.proxy.use_proxy" value="false"/>The password is "encrypted" with a reversible obfuscation scheme. Tools exist publicly to decode MID Server password values from config.xml. Once decoded, the attacker has a valid ServiceNow service account credential.
Authenticate to the ServiceNow instance using the MID Server service account. This account typically has the
mid_serverrole, which grants:- Read/write access to
ecc_queue(command injection — see ECC Queue Security & Message Manipulation) - Access to discovery credentials and schedules
- Ability to read probe results containing infrastructure data
- In many instances, additional roles granted for orchestration or CMDB writes
- Read/write access to
Inject commands into the ECC queue targeting other MID Servers, pivoting across network segments. A single compromised MID Server can be used to attack every other MID Server in the fleet.
Impact: Full instance access with MID Server privileges plus complete internal network pivot capability. The attacker controls both the cloud platform and the on-premise infrastructure bridge.
Attack Scenario 2: Disabling Certificate Validation via wrapper-override.conf
Precondition: Attacker has write access to the MID Server filesystem or can influence the auto-upgrade process.
Attack chain:
Modify wrapper-override.conf to disable SSL verification:
# wrapper-override.conf — attacker-injected lines wrapper.java.additional.50=-Djavax.net.ssl.trustAll=true wrapper.java.additional.51=-Dcom.glide.mid.ssl.verify_hostname=false wrapper.java.additional.52=-Djdk.tls.client.protocols=TLSv1,TLSv1.1,TLSv1.2Perform man-in-the-middle (MITM) attack between the MID Server and the ServiceNow instance. With certificate validation disabled, the attacker can intercept all traffic, including:
- ECC queue payloads containing discovery credentials
- Orchestration scripts with embedded secrets
- Authentication tokens for the ServiceNow instance
Alternatively, enable remote Java debugging to attach a debugger and inspect/modify MID Server behavior in real time:
wrapper.java.additional.60=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Impact: Complete interception of all data flowing between the organization's internal network and ServiceNow. Credential theft, command injection, and real-time manipulation of integration traffic.
Attack Scenario 3: Unvalidated MID Server Registration
Precondition: Attacker has network access to reach the ServiceNow instance (outbound HTTPS) and knows the instance URL. The instance does not enforce MID Server validation before accepting work.
Attack chain:
Deploy a rogue MID Server pointing to the target ServiceNow instance. If
mid.auto_validateis enabled or if the admin auto-approves the MID Server, it joins the fleet.The rogue MID Server receives all ECC queue commands targeted at its assigned name or application, including:
- Discovery probe parameters with credentials
- Orchestration scripts with infrastructure access
- Import set data containing sensitive records
The rogue MID Server returns fabricated results to the instance, poisoning the CMDB with false data, closing incidents prematurely, or injecting malicious data into workflows.
Impact: An attacker-controlled MID Server inside the trusted fleet can exfiltrate all integration credentials and poison the ServiceNow data model simultaneously.
How to Detect
MID Server Security Audit
/*
* INTEG-010 Detection Script
* Audits MID Server configurations, validation status, service accounts,
* certificate settings, and network exposure
*
* Run as: Background script with admin role
* Impact: Read-only, safe for production
* Versions: Washington+
*/
gs.info('=== INTEG-010: MID SERVER SECURITY AUDIT ===');
gs.info('Scan started: ' + new GlideDateTime().getDisplayValue());
gs.info('');
var totalFindings = 0;
var criticalFindings = 0;
// 1. MID Server inventory and validation status
gs.info('--- MID SERVER INVENTORY ---');
var mid = new GlideRecord('ecc_agent');
mid.query();
var midCount = 0;
var unvalidatedCount = 0;
var downCount = 0;
while (mid.next()) {
midCount++;
var name = mid.getValue('name');
var status = mid.getValue('status');
var validated = mid.getValue('validated');
var hostName = mid.getValue('host_name');
var ipAddress = mid.getValue('ip_address') || 'unknown';
var version = mid.getValue('version');
var userName = mid.getValue('user_name');
gs.info('MID Server: ' + name +
' | Status: ' + status +
' | Validated: ' + validated +
' | Host: ' + hostName +
' | IP: ' + ipAddress +
' | Version: ' + version +
' | Service Account: ' + userName);
if (validated !== 'true') {
gs.info(' [CRITICAL] MID Server is NOT validated — may be rogue');
criticalFindings++;
totalFindings++;
unvalidatedCount++;
}
if (status === 'Down') {
gs.info(' [WARNING] MID Server is DOWN — investigate if this is expected');
totalFindings++;
downCount++;
}
}
gs.info('Total MID Servers: ' + midCount +
' | Unvalidated: ' + unvalidatedCount +
' | Down: ' + downCount);
gs.info('');
// 2. MID Server service account privilege audit
gs.info('--- SERVICE ACCOUNT PRIVILEGE AUDIT ---');
var midUsers = {};
var midSA = new GlideRecord('ecc_agent');
midSA.query();
while (midSA.next()) {
var saUser = midSA.getValue('user_name');
if (saUser && !midUsers[saUser]) {
midUsers[saUser] = true;
}
}
for (var username in midUsers) {
var user = new GlideRecord('sys_user');
user.addQuery('user_name', username);
user.setLimit(1);
user.query();
if (user.next()) {
var roles = new GlideRecord('sys_user_has_role');
roles.addQuery('user', user.getUniqueValue());
roles.query();
var roleList = [];
while (roles.next()) {
var roleName = roles.getDisplayValue('role');
roleList.push(roleName);
}
gs.info('Service Account: ' + username +
' | Roles: ' + roleList.join(', '));
// Check for excessive privileges
var dangerousRoles = ['admin', 'security_admin', 'impersonator',
'soap', 'rest_api_explorer', 'sn_platform_admin'];
for (var r = 0; r < roleList.length; r++) {
for (var d = 0; d < dangerousRoles.length; d++) {
if (roleList[r].toLowerCase() === dangerousRoles[d]) {
gs.info(' [CRITICAL] Service account has dangerous role: ' +
roleList[r]);
criticalFindings++;
totalFindings++;
}
}
}
// Check if the account has admin role
if (roleList.join(',').toLowerCase().indexOf('admin') > -1) {
gs.info(' [CRITICAL] MID service account has admin-level access — ' +
'violates least privilege');
criticalFindings++;
totalFindings++;
}
}
}
gs.info('');
// 3. Check MID Server security properties
gs.info('--- MID SERVER SECURITY PROPERTIES ---');
var midProps = {
'mid.ssl.use.mutual.auth': {
safe: 'true',
risk: 'Mutual TLS not enforced — MID-to-instance channel vulnerable to MITM'
},
'mid.auto_validate': {
safe: 'false',
risk: 'MID Servers are auto-validated — rogue MID Server can join the fleet'
},
'glide.mid.auto_upgrade': {
safe: null,
risk: 'Auto-upgrade setting — verify upgrade source integrity'
},
'mid.ssl.bootstrap.default': {
safe: null,
risk: 'SSL bootstrap configuration — check certificate trust chain'
}
};
for (var prop in midProps) {
var val = gs.getProperty(prop, 'NOT SET');
gs.info(prop + ' = ' + val);
var config = midProps[prop];
if (config.safe && val !== config.safe && val !== 'NOT SET') {
gs.info(' [CRITICAL] ' + config.risk);
criticalFindings++;
totalFindings++;
} else if (val === 'NOT SET') {
gs.info(' [WARNING] ' + config.risk);
totalFindings++;
}
}
gs.info('');
// 4. Check for shared service accounts across MID Servers
gs.info('--- SHARED SERVICE ACCOUNT CHECK ---');
var saCount = {};
var midSACheck = new GlideRecord('ecc_agent');
midSACheck.query();
while (midSACheck.next()) {
var sa = midSACheck.getValue('user_name');
if (sa) {
saCount[sa] = (saCount[sa] || 0) + 1;
}
}
for (var account in saCount) {
if (saCount[account] > 1) {
gs.info('[WARNING] Service account "' + account +
'" is shared across ' + saCount[account] +
' MID Servers — compromise of one exposes all');
totalFindings++;
}
}
gs.info('');
// 5. Check MID Server cluster configuration
gs.info('--- MID SERVER CLUSTER CONFIGURATION ---');
var clusters = new GlideRecord('ecc_agent_cluster');
if (clusters.isValid()) {
clusters.query();
while (clusters.next()) {
gs.info('Cluster: ' + clusters.getValue('name') +
' | Members: ' + clusters.getValue('agents'));
}
}
gs.info('');
// 6. Audit recent MID Server status changes
gs.info('--- RECENT MID SERVER STATUS CHANGES (last 7 days) ---');
var midHistory = new GlideRecord('sys_audit');
midHistory.addQuery('tablename', 'ecc_agent');
midHistory.addQuery('fieldname', 'status');
midHistory.addQuery('sys_created_on', '>=', gs.daysAgo(7));
midHistory.orderByDesc('sys_created_on');
midHistory.setLimit(20);
midHistory.query();
while (midHistory.next()) {
gs.info('Status change: ' +
midHistory.getValue('oldvalue') + ' → ' +
midHistory.getValue('newvalue') +
' | MID: ' + midHistory.getDisplayValue('documentkey') +
' | By: ' + midHistory.getValue('user') +
' | When: ' + midHistory.getValue('sys_created_on'));
}
gs.info('');
// Summary
gs.info('=== SUMMARY ===');
gs.info('Total findings: ' + totalFindings);
gs.info('Critical findings: ' + criticalFindings);
gs.info('');
gs.info('RECOMMENDED ACTIONS:');
gs.info('1. Validate all MID Servers — remove or investigate unvalidated entries');
gs.info('2. Enable mutual TLS (mid.ssl.use.mutual.auth = true)');
gs.info('3. Disable auto-validation (mid.auto_validate = false)');
gs.info('4. Assign unique service accounts per MID Server with only mid_server role');
gs.info('5. Audit MID Server host filesystem permissions on config.xml');
gs.info('6. Segment MID Server network — restrict to required target hosts only');
Remediation
Step 1: Validate and Audit All MID Servers
1. Navigate to: MID Server > Servers
2. Review every MID Server record:
- Verify the host name and IP address are known infrastructure
- Confirm the MID Server is deployed by your team (not rogue)
- Check the validated field — set to true only for approved MID Servers
3. Delete or deactivate any unrecognized MID Server records
4. Disable auto-validation:
- Navigate to: sys_properties.LIST
- Set: mid.auto_validate = false
- This ensures every new MID Server requires explicit admin approval
5. Document each MID Server's purpose, network zone, and owner
Step 2: Harden config.xml and Service Account
1. Service account configuration:
- Create a UNIQUE service account per MID Server (e.g., mid.server.prod01)
- Assign ONLY the mid_server role — no admin, itil, or other roles
- Set a strong, unique password per account (32+ characters)
- Enable account lockout after failed authentication attempts
- Disable interactive login for the MID service account (web UI access)
2. config.xml security:
- Restrict filesystem permissions: readable only by the MID service account OS user
- Linux: chmod 600 config.xml; chown midserver:midserver config.xml
- Windows: NTFS permissions — only the service account user + Local Admins
- Monitor config.xml for unauthorized changes (file integrity monitoring)
- Never store config.xml in version control or backups accessible to non-admins
3. wrapper-override.conf security:
- Remove any lines containing: trustAll, verify_hostname=false, jdwp, debug
- Restrict write access to the same OS user running the MID Server
- Monitor for unauthorized modifications
Step 3: Enable Mutual TLS (Certificate Pinning)
1. Navigate to: MID Server > Properties
2. Set: mid.ssl.use.mutual.auth = true
- This requires the MID Server to present a client certificate when connecting
- The instance validates the certificate against a trusted store
3. Certificate deployment:
a. Generate a unique client certificate per MID Server
b. Sign with your organization's internal CA (or ServiceNow-provided CA)
c. Install the certificate in the MID Server's keystore:
- <MID_HOME>/agent/keystore/agent_keystore.jks
d. Configure the keystore password in config.xml:
- <parameter name="mid.ssl.keystore.password" value="[encrypted]"/>
e. Import the CA certificate into the instance's trust store
4. Validation:
- Restart the MID Server after certificate installation
- Verify MID Server status changes to "Up" with mutual auth enabled
- Test by attempting connection with an invalid certificate (should fail)
Step 4: Network Segmentation
1. Firewall rules for MID Server:
OUTBOUND (MID → Internet):
- Allow: HTTPS (443) to *.service-now.com ONLY
- Deny: All other outbound internet traffic
INBOUND (to MID Server):
- Deny: ALL inbound connections (MID Server initiates all connections)
- Exception: Management access from jump hosts only (SSH/RDP)
INTERNAL (MID → Target Systems):
- Allow: ONLY the specific ports/protocols needed for discovery/orchestration
- Example: SSH (22), WMI (135/5985/5986), SNMP (161), JDBC (1433/1521/3306)
- Restrict to ONLY the target IP ranges the MID Server needs to reach
- Deny: All other internal traffic
2. Network monitoring:
- Alert on MID Server communicating with unexpected internal hosts
- Alert on MID Server making unexpected outbound connections
- Log all MID Server network traffic for forensic analysis
3. DNS:
- MID Server should resolve *.service-now.com only via trusted DNS
- Consider DNS pinning to prevent DNS-based MITM
Step 5: Control Auto-Upgrade Behavior
1. Evaluate auto-upgrade risk:
- Auto-upgrade ensures MID Servers receive security patches
- BUT: the upgrade payload is downloaded from ServiceNow and executed
- A compromised upgrade channel could deploy malicious code
2. Recommended configuration:
- Enable auto-upgrade for security patch velocity: glide.mid.auto_upgrade = true
- BUT: monitor upgrade events and version changes
- Create an alert when MID Server version changes unexpectedly
3. Alternative for high-security environments:
- Disable auto-upgrade: glide.mid.auto_upgrade = false
- Manually download and validate MID Server installers
- Deploy upgrades through your change management process
- Test upgrades in sub-production before production deployment
Post-Remediation Verification
/*
* Verify MID Server security hardening
*/
gs.info('=== INTEG-010: POST-REMEDIATION CHECK ===');
var issues = 0;
// Check all MID Servers are validated
var midCheck = new GlideRecord('ecc_agent');
midCheck.addQuery('validated', '!=', 'true');
midCheck.query();
if (midCheck.hasNext()) {
gs.info('FAIL: Unvalidated MID Servers still exist');
issues++;
} else {
gs.info('PASS: All MID Servers are validated');
}
// Check mutual TLS
var mutualAuth = gs.getProperty('mid.ssl.use.mutual.auth', 'false');
if (mutualAuth !== 'true') {
gs.info('FAIL: Mutual TLS not enabled (mid.ssl.use.mutual.auth = ' + mutualAuth + ')');
issues++;
} else {
gs.info('PASS: Mutual TLS is enabled');
}
// Check auto-validate is disabled
var autoValidate = gs.getProperty('mid.auto_validate', 'NOT SET');
if (autoValidate === 'true') {
gs.info('FAIL: Auto-validation is enabled — rogue MID Servers can join automatically');
issues++;
} else {
gs.info('PASS: Auto-validation is disabled or not set');
}
// Check for shared service accounts
var saCounts = {};
var midSA = new GlideRecord('ecc_agent');
midSA.query();
while (midSA.next()) {
var sa = midSA.getValue('user_name');
saCounts[sa] = (saCounts[sa] || 0) + 1;
}
var sharedAccounts = false;
for (var account in saCounts) {
if (saCounts[account] > 1) {
gs.info('FAIL: Shared service account "' + account +
'" used by ' + saCounts[account] + ' MID Servers');
issues++;
sharedAccounts = true;
}
}
if (!sharedAccounts) {
gs.info('PASS: No shared MID Server service accounts');
}
// Check service account roles
var midAccounts = new GlideRecord('ecc_agent');
midAccounts.query();
while (midAccounts.next()) {
var userName = midAccounts.getValue('user_name');
var userRec = new GlideRecord('sys_user');
userRec.addQuery('user_name', userName);
userRec.setLimit(1);
userRec.query();
if (userRec.next()) {
var hasAdmin = new GlideRecord('sys_user_has_role');
hasAdmin.addQuery('user', userRec.getUniqueValue());
hasAdmin.addQuery('role.name', 'admin');
hasAdmin.setLimit(1);
hasAdmin.query();
if (hasAdmin.hasNext()) {
gs.info('FAIL: MID Server account "' + userName + '" has admin role');
issues++;
}
}
}
gs.info(issues === 0 ? 'ALL CHECKS PASSED' : 'FAILED: ' + issues + ' issues remaining');
Regulatory Impact
NIS2 Mapping
| Article | Requirement | How MID Server Weakness Violates It | Evidence After Fix |
|---|---|---|---|
| Art.21§2(d) | Supply chain security | Compromised MID Server provides pivot access to entire supply chain infrastructure; config.xml credential theft cascades through all connected systems | Mutual TLS enforced; unique service accounts per MID Server; config.xml filesystem hardened; network segmented |
DORA Mapping
| Article | Requirement | How MID Server Weakness Violates It | Evidence After Fix |
|---|---|---|---|
| Art.9§4(d) | ICT operations security | MID Server config files contain reversible credentials; unvalidated MID Servers can join fleet; no certificate pinning by default | Certificate pinning enabled; auto-validation disabled; config.xml access restricted; file integrity monitoring deployed |
ISO 27001:2022 Mapping
| Control | Requirement | How MID Server Weakness Violates It | Evidence After Fix |
|---|---|---|---|
| A.8.9 | Configuration management | MID Server security configuration not baselined; wrapper-override.conf can disable security controls without detection | MID Server hardening baseline documented; config file monitoring; wrapper-override.conf locked down |
Expert Notes
Practitioner annotations pending -- article content has been technically validated.