Someone left the back door to the security-camera control room unlocked, but you have to be inside the building to reach it
CVE-2026-28325 is an unauthenticated remote code execution flaw in SolarWinds Observability Self-Hosted (all versions before 2026.2.3) caused by classic CWE-502 deserialization of untrusted data. The vulnerability lives in the WPM (Web Performance Monitor) passive-player communication channel — specifically port 17781, used when WPM players operate in server-initiated (passive) mode. An attacker on the adjacent network can send a crafted serialized payload to this listener and achieve code execution as the SolarWinds service account, with no authentication required. The companion flaw CVE-2026-28324 (CVSS 9.8) addresses a related insufficient-integrity-check issue in a separate non-default configuration. Both were reported by Kai Huang of Armadin and patched on 2026-09-22.
SolarWinds rates this HIGH at 8.8, and the CVSS vector is honest: AV:A correctly reflects adjacent-network-only reachability, which is a significant constraint. However, the vector uses AC:L despite the exploit requiring a *specific non-default communication mode* (passive WPM players) — CVSS 3.1 doesn't model configuration prerequisites well, so the 8.8 slightly overstates real-world likelihood. That said, SolarWinds Observability is a monitoring platform that stores polling credentials (SNMP, WMI, SSH, SQL) for potentially every managed device on the network; compromising it gives an attacker a credential vault and a topology map of the entire environment. The post-SUNBURST world means SolarWinds compromise carries outsized reputational and operational blast radius. The vendor severity is directionally correct but numerically generous by about one point.
5 steps from start to impact.
Adjacent network position
AV:A, meaning this is not exploitable from the public internet. In practice this means a compromised workstation, VPN foothold, or rogue device on the management VLAN.- Adjacent network access to the SolarWinds server or its polling engine
- Requires prior compromise or physical access to the management network
- Most enterprises isolate monitoring infrastructure on a dedicated management VLAN with ACLs
Identify passive WPM player listener
nmap -p 17781 reveals the target.- WPM module installed and at least one passive player configured in server-initiated mode
- Passive mode is not universally adopted — player-initiated mode is recommended for distributed/MSP deployments
- Deployments without WPM module are not affected at all
Craft deserialization payload
- Knowledge of the deserialization format used by the WPM passive channel
- No public PoC yet — attacker must develop or reverse-engineer the protocol
- No public PoC or exploit code available as of 2026-09-24
- Protocol-specific serialization format requires reverse engineering of the SolarWinds binary
Code execution as SolarWinds service account
NT AUTHORITY\SYSTEM or a high-privilege service account with access to the SolarWinds configuration database, credential store, and the ability to communicate with all managed nodes via polling protocols (SNMP, WMI, SSH, SQL).- Successful delivery of the deserialization payload to the vulnerable endpoint
- EDR on the SolarWinds server should detect anomalous process creation from the SolarWinds service
- Application whitelisting would block unexpected binaries
Credential harvesting and lateral movement
- Access to the SolarWinds configuration database
- Stored credentials not externally vaulted
- Organizations using external credential vaults (CyberArk, HashiCorp Vault) limit stored secrets
- Network segmentation between the monitoring tier and production tiers
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed on CISA KEV. No campaigns or threat actor attribution as of 2026-09-24. CISA SSVC marks the companion CVE-2026-28324 as 'automatable' but does not flag CVE-2026-28325 the same way. |
|---|---|
| Proof-of-Concept | No public PoC. No exploit code found on GitHub, Exploit-DB, or researcher blogs. The underlying technique (.NET deserialization via ysoserial.net) is well-known, but the protocol-specific payload for WPM passive-player communication has not been published. |
| EPSS Score | 0.01518 (1.518%) — 27th percentile. Indicates low predicted exploitation probability in the next 30 days. |
| KEV Status | Not listed. As of 2026-09-24, CVE-2026-28325 is not on the CISA Known Exploited Vulnerabilities catalog. |
| CVSS Vector | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — Adjacent network vector is the key constraint. Full CIA impact but scope unchanged. The AC:L is debatable given the config prerequisite. |
| Affected Versions | All SolarWinds Observability Self-Hosted versions prior to 2026.2.3. End-of-support versions (2024.2 and earlier) will not receive fixes. |
| Fixed Version | 2026.2.3 (released 2026-09-22). The patch migrates default passive WPM players to player-initiated (active) communication and generates strong random passwords for remotely installed passive players. |
| Scanning / Exposure | No GreyNoise or Shodan data specific to port 17781 scanning. The WPM passive-player port is an internal service not typically exposed to the internet. SolarWinds Observability Self-Hosted ranks 2nd of 53 in the infrastructure monitoring category per 6sense/FitGap, with significant enterprise installed base. |
| Disclosure Date | 2026-09-22 — coordinated disclosure via SolarWinds security advisory alongside CVE-2026-28324. |
| Reporter | Kai Huang of Armadin — reported both CVE-2026-28324 and CVE-2026-28325 through responsible disclosure. |
Sources.
- GBHackers — SolarWinds Observability Flaws Let Unauthenticated Attackers Execute Remote Code
- SecurityOnline — SolarWinds Observability Vulnerabilities Patched
- Mallory.ai — SolarWinds Observability Self-Hosted Patches Critical Unauthenticated RCE
- OffSeq Threat Radar — CVE-2026-28325 Live Threat Intelligence
- Strix.ai — CVE-2026-28325 Detail
- SolarWinds Documentation — WPM Player Communication Settings
- SolarWinds Documentation — Agent Communication Modes
- SolarWinds — Observability Self-Hosted 2026.2 Release Notes
Why this verdict
- Adjacent-network constraint already priced in, but config gate is not. The CVSS vector correctly uses
AV:A, butAC:Ldoes not account for the prerequisite that passive WPM player communication mode must be enabled — a specific, non-universal configuration. This shaves ~1 point off the vendor's 8.8. - No PoC, no exploitation, low EPSS. At 1.5% EPSS with zero public exploit code and no KEV listing, the near-term weaponization risk is low. An attacker would need to reverse-engineer the WPM passive-player protocol to build a working exploit.
- Post-initial-access positioning required.
AV:Aimplies the attacker is already inside the network perimeter — this is a second-stage exploit, not an initial-access vector. The attacker needs a prior foothold on the management VLAN. - Management VLAN segmentation is common friction. Enterprise SolarWinds deployments are typically isolated on management VLANs with restricted access. The adjacent-network requirement further narrows the reachable population.
- Role multiplier: SolarWinds Observability is canonically a high-value monitoring platform. ≥80% of installs ARE the production monitoring instance. Compromise yields stored polling credentials (SNMP, WMI, SSH, SQL) for the entire monitored fleet — blast radius is host → fleet. This is analogous to SIEM/detection-plane compromise. The credential-store pivot makes this a domain/fleet-scale outcome when the chain lands. Verdict floor: HIGH. The chain does succeed in the high-value role with fleet-scale blast radius, but AV:A + config gate + no PoC keep it at the floor rather than pushing to CRITICAL.
Why not higher?
CRITICAL would require either internet-reachable attack surface or active exploitation. This CVE has neither — AV:A confines it to adjacent-network attackers, the passive WPM player mode is a non-universal configuration prerequisite, and there is zero evidence of weaponization. The companion CVE-2026-28324 at 9.8 is the more dangerous of the pair and may warrant separate assessment.
Why not lower?
SolarWinds Observability is a canonical high-value target that stores credentials for the entire monitored infrastructure. Compromise of this platform is not a single-host event — it is a fleet-credential-harvesting event analogous to domain controller compromise. The .NET deserialization primitive is commodity-grade even without a public PoC, and the SUNBURST precedent demonstrates that SolarWinds platforms are actively targeted by sophisticated adversaries. Dropping below HIGH would ignore the blast-radius floor.
cmd.exe, powershell.exe, certutil.exe spawned by SolarWinds.BusinessLayerHost.exe).- WAF / reverse proxy in front of SolarWinds — this vulnerability is on port 17781 (WPM passive-player protocol), not the web console. A WAF protecting the SolarWinds web UI on port 443 does not intercept traffic to the WPM communication channel.
- Upgrading WPM players only without upgrading the main server — the deserialization flaw is in the server-side handler that processes incoming data from passive players. Upgrading only the remote WPM player agents does not fix the vulnerable endpoint.
- Network-level IPS with generic deserialization signatures — .NET BinaryFormatter deserialization payloads are highly polymorphic and protocol-wrapped; generic IPS signatures have poor detection rates for custom serialization protocols like the WPM passive channel.
Crowdsourced verification payload.
Run this script on each SolarWinds Observability Self-Hosted server and Additional Polling Engine (APE) as a local administrator. Invoke with: powershell -ExecutionPolicy Bypass -File .\Check-CVE-2026-28325.ps1. The script checks the installed product version and whether the vulnerable WPM passive-player listener is active on port 17781.
#Requires -RunAsAdministrator
<#
Check-CVE-2026-28325.ps1
Checks SolarWinds Observability Self-Hosted for CVE-2026-28325 exposure.
Outputs: VULNERABLE / PATCHED / UNKNOWN
Exit codes: 1 = VULNERABLE, 0 = PATCHED, 2 = UNKNOWN
#>
$ErrorActionPreference = 'SilentlyContinue'
$status = 'UNKNOWN'
$reasons = @()
# Step 1: Detect SolarWinds installation and version
$swRegPaths = @(
'HKLM:\SOFTWARE\SolarWinds\Orion\Core',
'HKLM:\SOFTWARE\WOW6432Node\SolarWinds\Orion\Core'
)
$installedVersion = $null
foreach ($p in $swRegPaths) {
$reg = Get-ItemProperty -Path $p -ErrorAction SilentlyContinue
if ($reg -and $reg.Version) {
$installedVersion = $reg.Version
break
}
}
if (-not $installedVersion) {
# Fallback: check for SolarWinds services
$swService = Get-Service -Name 'SolarWinds*' -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $swService) {
Write-Host '[*] SolarWinds Observability Self-Hosted does not appear to be installed.'
Write-Host 'PATCHED'
exit 0
}
$reasons += 'Could not determine installed version from registry'
}
# Step 2: Check if WPM passive player listener is active on port 17781
$port17781 = Get-NetTCPConnection -LocalPort 17781 -State Listen -ErrorAction SilentlyContinue
$passivePlayerActive = $false
if ($port17781) {
$passivePlayerActive = $true
$reasons += 'WPM passive-player listener ACTIVE on port 17781 (vulnerable communication mode)'
} else {
$reasons += 'Port 17781 not listening (passive WPM player mode not active)'
}
# Step 3: Version comparison
$fixedVersion = '2026.2.3'
if ($installedVersion) {
$reasons += "Installed version: $installedVersion"
# Normalize version for comparison (handle YYYY.M.P format)
try {
$installed = [version]($installedVersion -replace '^(\d{4})\.(\d+)\.(\d+).*', '$1.$2.$3')
$fixed = [version]$fixedVersion
if ($installed -ge $fixed) {
$status = 'PATCHED'
$reasons += "Version $installedVersion >= $fixedVersion (patched)"
} else {
$status = 'VULNERABLE'
$reasons += "Version $installedVersion < $fixedVersion (unpatched)"
}
} catch {
$reasons += "Could not parse version string: $installedVersion"
if ($passivePlayerActive) {
$status = 'VULNERABLE'
} else {
$status = 'UNKNOWN'
}
}
} else {
# No version found but SolarWinds services exist
if ($passivePlayerActive) {
$status = 'VULNERABLE'
$reasons += 'Cannot confirm version but vulnerable communication mode is active'
} else {
$status = 'UNKNOWN'
$reasons += 'Cannot confirm version; passive player mode not active (reduced risk)'
}
}
# Step 4: Additional context — check if patched behavior is present
if ($status -eq 'PATCHED' -and $passivePlayerActive) {
$reasons += 'WARNING: Patched version detected but port 17781 still listening — verify WPM player migration completed'
$status = 'VULNERABLE'
}
Write-Host ''
Write-Host '=== CVE-2026-28325 Check ==='
Write-Host "Result: $status"
foreach ($r in $reasons) { Write-Host " - $r" }
Write-Host ''
Write-Host $status
switch ($status) {
'VULNERABLE' { exit 1 }
'PATCHED' { exit 0 }
default { exit 2 }
}