An expired janitor keychain that still opens every closet in the building
CVE-2026-10538 is a CWE-502 unsafe deserialization flaw in the messaging consumer of BMC Control-M/Server and Control-M/Enterprise Manager (EM), versions 9.0.20.x and earlier — all of which are already out of vendor support. A user who has already authenticated with high privileges can post a crafted serialized Java object into the messaging channel and cause the consumer to instantiate arbitrary types, leading to server-side behavior the operator never authorized. Because Control-M is an orchestration plane that fans out to a fleet of Control-M/Agent endpoints, S:C (scope change) here is not theoretical — the compromised process can reach into the jobs it schedules.
The vendor's HIGH / 8.0 call is defensible and roughly matches reality. It does not deserve a CRITICAL upgrade because AC:H and PR:H in the vector are real: you need a working admin session on a legacy platform, and the message path is not an unauthenticated Internet listener. It does not deserve a downgrade to MEDIUM either, because the blast radius when the chain does land — arbitrary code inside the job orchestrator that pushes commands to production agents — is fleet-wide. Net: unchanged, HIGH.
5 steps from start to impact.
Reach the Control-M/EM messaging endpoint
- Routable path to Control-M messaging port from attacker position
- Control-M/Server or EM at 9.0.20.x or earlier (unsupported)
- Management planes are typically on isolated VLANs with ACLs
- Requires the attacker to already hold an internal foothold
Authenticate with a high-privilege Control-M account
PR:H — a valid operator/administrator credential in Control-M itself, not just OS-level access. Attackers get here via credential theft from a Control-M operator workstation (mimikatz, LaZagne), reused domain credentials via Rubeus/Impacket, or by pivoting from a compromised BMC AD group.- Valid Control-M admin credentials
- Auth channel reachable (see step 1)
- Control-M admin accounts are typically small in number and audited
- MFA on Control-M console (where enabled) blocks credential replay
Publish a crafted serialized payload to the messaging consumer
ysoserial-style gadget chain — CommonsBeanutils1, CommonsCollections6, Hibernate1, whichever gadget classes ship in the Control-M classpath) into the messaging consumer. Because the consumer deserializes without an allow-list of expected object types, gadget invocation runs during readObject().- Gadget-class present on Control-M classpath
- Consumer accepts attacker-controlled serialized bytes
AC:H— the attacker must know or fingerprint the classpath to pick a working gadget- Newer JVM security manager settings and
jdk.serialFilterallow-lists mitigate broad gadgets
java.exe/javaw.exe spawning cmd.exe/powershell.exe//bin/sh.Execute code in the Control-M/Server service context
controlm UNIX account with sudo carveouts. From here the attacker has read/write on the Control-M database, job definitions, and agent configuration.- Deserialization gadget successfully invoked
- Application-allowlisting (WDAC, AppLocker, Carbon Black) on the Control-M host may block secondary payload staging
ControlM* parents is high-signal; almost no legitimate reason for shells to spawn under the JVM.Pivot to the managed agent fleet
Control-M/Agent hosts by design. The attacker submits malicious jobs (ctmcreate, ctmjsa) or edits scheduled tables to run arbitrary commands as the agent's execution user across hundreds or thousands of downstream servers — including production DB tiers, batch nodes, and ETL workers.- Job creation/execution privilege inside the compromised Control-M/Server
- Agents that pin execution to specific users limit blast radius per host, but not aggregate reach
ctmagent outside of the change window.The supporting signals.
| In-the-wild exploitation | No public exploitation reported as of 2026-07-01. No campaign attribution from Mandiant, CrowdStrike, or Unit 42. |
|---|---|
| Public PoC | None published. Deserialization gadget delivery is well-understood (ysoserial, marshalsec), but no Control-M–specific weaponization is public. |
| EPSS | Expected <0.5% at disclosure (fresh CVE, no PoC, niche platform); recheck FIRST feed in 7 days. |
| KEV status | Not listed on CISA KEV as of 2026-07-01. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H — network vector but gated by high complexity and admin auth; scope change is the reason it clears 8.0. |
| Affected versions | Control-M/Server and Control-M/Enterprise Manager 9.0.20.x and potentially earlier — all out of support. |
| Fixed versions | Upgrade to a currently supported Control-M release (9.0.21 LTS or later, per BMC lifecycle). No backport for 9.0.20.x. |
| Exposure telemetry | Shodan/Censys show negligible public exposure of Control-M messaging ports — this is a management-plane service, near-zero internet-facing installs. |
| Disclosure date | 2026-07-01 — published today by BMC via advisory KA 000442099. |
| Reporter | Credit per BMC advisory; independent researcher submission through BMC PSIRT. |
noisgate verdict.
The single decisive factor is role multiplier: Control-M is an enterprise job orchestrator whose compromise fans out to the entire managed agent fleet, which floors this at HIGH regardless of the authenticated-admin friction. It does not clear the CRITICAL bar because PR:H plus AC:H plus the affected code path existing only on out-of-support 9.0.20.x narrows both attacker eligibility and installed base.
Why this verdict
- Role multiplier — Control-M is orchestration-tier: The affected component sits alongside Jenkins/GitLab Runner/Airflow in the high-value-role catalog. A successful chain ends in job pushes across the entire agent fleet — DB tiers, batch nodes, ETL. Floor is HIGH.
- Authenticated with high privilege (PR:H) — real friction, not decorative: The attacker must already hold a Control-M admin credential. This is not a network-edge unauthenticated bug; it presumes a prior compromise stage (credential theft, insider). Keeps the verdict off CRITICAL.
- Attack complexity is genuinely high (AC:H): Deserialization needs a viable gadget chain against the specific JVM/classpath shipped with Control-M 9.0.20.x. Not a spray-and-pray primitive.
- Affected population is narrow — EOL only: BMC scopes this to out-of-support 9.0.20.x. Organizations on the current LTS are not affected. That narrows installed base but does not zero it — legacy Control-M in regulated industries is common.
- No KEV, no PoC, no exposure telemetry: Zero in-the-wild indicators and negligible Internet exposure (management-plane service). Prevents a KEV-driven upgrade to CRITICAL.
Why not higher?
CRITICAL is reserved for reachable-from-anywhere or already-exploited primitives. This requires an authenticated Control-M admin session (PR:H), targets an EOL SKU only, and shows no exploitation. Elevating to CRITICAL would over-signal against fresher, unauthenticated bugs competing for the same patch window.
Why not lower?
MEDIUM understates the blast radius. Control-M isn't a line-of-business server — code execution in its service context yields job-push authority across the managed fleet, so the impact when the chain does land is fleet-scale. The role multiplier floors this at HIGH.
What to do — in priority order.
- Firewall the Control-M messaging ports to a named jump-host allowlist — Restrict the EM Gateway and Control-M/Server listener to a small set of admin bastions. This immediately removes lateral reachability from the general corporate LAN. Deploy within 30 days per noisgate mitigation SLA.
- Force MFA + step-up on all Control-M administrator accounts — The chain requires
PR:H— kill credential replay by requiring MFA at the EM console and rotating any admin credentials that ever touched a workstation. Complete within 30 days. - Enable a strict
jdk.serialFilterallow-list on the Control-M JVM — Set-Djdk.serialFilter=to reject known gadget class prefixes (org.apache.commons.collections.*,org.apache.commons.beanutils.*,com.sun.rowset.*,org.hibernate.*). Blocks the deserialization primitive even if authentication is bypassed. Apply within 30 days. - Enable Control-M audit log forwarding to SIEM with admin-logon alerts — Detect anomalous admin authentications from unusual hosts or off-hours. Do this in the same 30-day window so you can attribute any exploit attempt after the fact.
- Schedule the LTS upgrade off the 9.0.20.x branch — 9.0.20.x is out of support — the fix is to move to a supported LTS train. Plan the maintenance window inside the noisgate remediation SLA (≤ 180 days).
- WAF / reverse proxy rules — the messaging channel is not HTTP, so WAFs (F5 ASM, Cloudflare, Akamai) do not inspect it.
- Network-level IPS signatures for
ysoserial— Control-M messaging is not raw HTTP POST; generic Suricata/Snort deserialization rules will not trigger. - Disabling anonymous access — the flaw already requires
PR:H; anonymous access is not the vector. - EDR alone — process-spawn heuristics on the JVM host help post-compromise, but they don't stop the deserialization primitive itself.
Crowdsourced verification payload.
Run on the target Control-M/Server or Control-M/EM host as a local administrator. Invoke as .\Check-CVE-2026-10538.ps1 -InstallRoot 'C:\Program Files\BMC Software\Control-M EM'. The script inspects install version metadata and reports VULNERABLE for 9.0.20.x or earlier, PATCHED for supported LTS, UNKNOWN if it cannot resolve the version.
#requires -Version 5.1
# Check-CVE-2026-10538.ps1
# Determines whether a Control-M/Server or Control-M/EM install is exposed to CVE-2026-10538.
param(
[string]$InstallRoot = 'C:\Program Files\BMC Software\Control-M EM'
)
$ErrorActionPreference = 'Stop'
function Get-ControlMVersion {
param([string]$Root)
$verFile = Join-Path $Root 'version.txt'
if (Test-Path $verFile) {
return (Get-Content $verFile -Raw).Trim()
}
# Fall back to registry
$regPaths = @(
'HKLM:\SOFTWARE\BMC Software\Control-M\EnterpriseManager',
'HKLM:\SOFTWARE\BMC Software\Control-M\Server'
)
foreach ($p in $regPaths) {
if (Test-Path $p) {
$v = (Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).Version
if ($v) { return $v }
}
}
return $null
}
$version = Get-ControlMVersion -Root $InstallRoot
if (-not $version) {
Write-Output 'UNKNOWN - could not resolve Control-M version'
exit 2
}
Write-Output "Detected Control-M version: $version"
# CVE-2026-10538 affects 9.0.20.x and earlier (all EOL)
if ($version -match '^(9\.0\.(1[0-9]|20)(\.|$))|^([0-8]\.)') {
Write-Output 'VULNERABLE'
exit 1
}
elseif ($version -match '^9\.0\.2[1-9]' -or $version -match '^(1[0-9]|[2-9][0-9])\.') {
Write-Output 'PATCHED'
exit 0
}
else {
Write-Output 'UNKNOWN - version string did not match known ranges'
exit 2
}
If you remember one thing.
jdk.serialFilter allow-list on the Control-M JVM in the same window. (4) Book the LTS upgrade off 9.0.20.x inside the noisgate remediation SLA of ≤ 180 days — this is your real fix, since no backport exists for the unsupported branch. If your CTI feed later shows KEV listing or a public gadget chain for Control-M, override both windows to *hours*, not days.Sources
- BMC Control-M/Agent Security Update announcement
- CISA Weekly Vulnerability Summary (SB26-173)
- MITRE CWE-502: Deserialization of Untrusted Data
- ysoserial gadget chain reference (Frohoff)
- OpenJDK Serialization Filtering (`jdk.serialFilter`)
- CISA Known Exploited Vulnerabilities Catalog
- FIRST EPSS model and data feed
- BMC Control-M version list (cvedetails)
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.