A SharePoint user smuggles a compiler directive inside a workflow definition and the server obediently builds it into native code
CVE-2020-0646 is an input-validation flaw in the Microsoft .NET Framework Workflow Compiler as invoked by SharePoint when processing XOML (Extensible Object Markup Language) workflow definitions. An authenticated SharePoint user with rights to create or edit a workflow can inject crafted XML that the server-side compiler treats as code, yielding RCE as the SharePoint application pool identity (typically the farm or web-app service account). Affected: .NET Framework 3.5 / 4.5.2 / 4.6 / 4.6.2 / 4.7 / 4.7.1 / 4.7.2 / 4.8 across Windows client and Server SKUs, and SharePoint Server 2010 SP2 / 2013 SP1 / 2016 / 2019 prior to the January 2020 cumulative update.
Vendor labels this 9.8 / Critical with PR:N, which is misleading: MSRC's own write-up and MDSec's PoC require an authenticated SharePoint principal that can submit a workflow. Reality is closer to AV:N / PR:L / UI:N / RCE — i.e., a high authenticated bug, not a drive-by. That said, EPSS 0.992, KEV listing, public Metasploit module, and the canonical SharePoint role (identity-adjacent, frequently service-account-rich) keep this firmly in HIGH territory.
4 steps from start to impact.
Acquire a SharePoint foothold account
- Reachable SharePoint web front-end (intranet or via VPN/ZTNA)
- Valid AD/Entra credentials with site-level workflow permissions
- MFA on the IdP blocks most credential-stuffing
- ZTNA/conditional access removes most public exposure
- Many farms restrict workflow-author role to a small group
Craft malicious XOML workflow
exploit/windows/http/sharepoint_workflows_xoml, the attacker builds a XOML payload that injects <x:Code> (or equivalent compiler directive) into the workflow XML. SharePoint passes this to the Workflow Compiler, which fails to strip code blocks before invoking csc.exe.- Knowledge of target site URL and a writable workflow list
- WAF rules with XOML/
<x:Code>signatures can block the upload - SharePoint hardening that disables sandboxed/declarative workflows
csc.exe invocations parented to w3wp.exe.Submit workflow and trigger compilation
/_vti_bin/... or /_layouts/15/WrkStat.aspx-adjacent handlers). The Workflow Compiler runs server-side, compiles the embedded C# into an assembly, and loads it in the SharePoint worker process, executing arbitrary code as the app pool identity.- Server has not received the January 2020 .NET / SharePoint CU
- Patched farms reject the embedded
<Code>element outright - Restricted IIS app-pool identities limit lateral movement
Pivot from app pool to farm and AD
- Service account is over-privileged or has SPN-based delegation
- Properly scoped gMSA/MSA service accounts with no logon-as-batch rights elsewhere
- Tiered admin model
The supporting signals.
| In-the-wild status | KEV-listed by CISA; observed in opportunistic SharePoint compromise campaigns since 2020. Pairs frequently with CVE-2019-0604 in the same intrusion sets. |
|---|---|
| Public PoC | Detailed write-up + PoC by Soroush Dalili (MDSec, Jan 2020); Metasploit module exploit/windows/http/sharepoint_workflows_xoml (rapid7/metasploit-framework PR #13122 by zeroSteiner). |
| EPSS | 0.99193 — top ~0.5 percentile; among the most-exploited CVEs tracked by FIRST. |
| CISA KEV | Listed; remediation required for federal agencies under BOD 22-01. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 Critical. Real-world PR is L (workflow author), not N — adjusted score closer to 8.5. |
| Affected versions | .NET Framework 3.5, 4.5.2, 4.6, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8 on Windows 7/8.1/10/Server 2008–2019; SharePoint 2010 SP2, 2013 SP1, 2016, 2019 pre-Jan 2020 CU. |
| Fixed in | Microsoft January 2020 Patch Tuesday (KB4534271 / KB4534976 / KB4535102 family for .NET; KB4484149 / KB4484142 / KB4484113 for SharePoint). |
| Exposure (Shodan/Censys) | ~250k SharePoint instances reachable on the public internet per Shodan; majority sit behind SSO/Entra, but legacy on-prem SharePoint 2013/2016 farms remain heavily represented. |
| Disclosure | Coordinated disclosure 14 Jan 2020 (Microsoft Patch Tuesday). NVD record updated 2022-05-24. |
| Reporter | Soroush Dalili (@irsdl), MDSec ActiveBreach. |
noisgate verdict.
The decisive factor is the authenticated-user prerequisite — the chain requires a SharePoint principal with workflow-author rights, not an unauthenticated internet attacker, which is why this lands at HIGH rather than CRITICAL despite the 9.8 vendor score. The role multiplier prevents any further downgrade: SharePoint farms run with domain-joined, frequently over-privileged service accounts, so the blast radius from a single RCE routinely extends into AD.
Why this verdict
- Authentication required, not PR:N: MDSec's PoC and the Metasploit module both need a workflow-author principal. The CVSS
PR:Nclaim does not survive contact with the source research — this is the single biggest reason for the downgrade from 9.8. - KEV + EPSS 0.992: active, repeatable exploitation in the wild; ignoring this entirely is not defensible even with the auth prerequisite.
- Role multiplier — SharePoint as identity-adjacent tier: SharePoint farm accounts are domain users, often with read access to AD attributes, mailbox enumeration via Graph, and SPNs that invite Kerberoasting. RCE in
w3wp.exeis a credible launchpad to domain compromise, which floors this at HIGH. - Compensating friction: most modern farms front SharePoint with Entra SSO + MFA + Conditional Access; the attacker must first land a valid corporate identity, which is non-trivial but not rare.
- Patch is six years old: any unpatched farm is by definition outside normal lifecycle and likely has additional 2019-era SharePoint bugs (CVE-2019-0604) co-resident.
Why not higher?
CRITICAL would require unauthenticated reachable RCE on a widely-exposed component. The auth requirement collapses the candidate population to existing employees / contractors / partners with workflow rights, and most SharePoint farms are not internet-facing in 2026.
Why not lower?
MEDIUM is wrong because KEV listing and EPSS 0.992 reflect ongoing real-world abuse, and the role multiplier (SharePoint farm service account → AD) means a successful chain is not contained to a single host.
What to do — in priority order.
- Apply January 2020 (or later) SharePoint + .NET cumulative updates — This is the only durable fix. Under the noisgate remediation SLA for HIGH, complete farm-wide patching within 180 days; if any farm is internet-reachable, treat as KEV override and patch within hours.
- Block declarative/sandboxed workflow creation for non-admin users — In Central Admin → Web Application General Settings, disable user-defined workflows on web apps that don't need them. Removes the primary attack surface even on unpatched farms. Deploy within 30 days per noisgate mitigation SLA for HIGH.
- Put SharePoint behind Entra Application Proxy / ZTNA with MFA + device compliance — Eliminates anonymous internet exposure and raises the cost of acquiring the workflow-author foothold. Conditional-access policies should require compliant device for any non-read action.
- Constrain SharePoint farm and app-pool service accounts — Convert to gMSA, strip local admin on non-WFE hosts, remove SPN-based unconstrained/constrained delegation, and add to Protected Users where compatible. Limits blast radius post-RCE.
- Deploy WAF rules blocking
<x:Code>/Code=in XOML POSTs — F5 ASM, Azure WAF, and Imperva all have rules for this CVE family — enable in blocking (not detect-only) mode.
- Disabling anonymous access alone — exploitation is authenticated; anonymous lockdown doesn't help.
- EDR on the WFE without baselining
csc.exeparented byw3wp.exe—csc.exeis occasionally legitimate during ASP.NET runtime compilation; you need a specific detection, not generic process-tree alerts. - Network IDS signatures looking for
.xomlextensions — payload is delivered via SOAP/REST endpoints, not as a file upload with that extension.
Crowdsourced verification payload.
Run on each SharePoint WFE / app server as a local admin (or via PSRemoting from an auditor workstation: Invoke-Command -ComputerName SP01 -ScriptBlock { ... }). Script inspects installed .NET Framework build and SharePoint CU level against the January 2020 fix baseline. Outputs VULNERABLE, PATCHED, or UNKNOWN.
#requires -RunAsAdministrator
# noisgate verification: CVE-2020-0646 (.NET Framework / SharePoint XOML RCE)
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
$ErrorActionPreference = 'Stop'
$verdict = 'UNKNOWN'
try {
# --- .NET Framework 4.x build check (fix shipped Jan 14 2020) ---
$ndp = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue
$release = $ndp.Release
# Jan-2020 servicing baselines: 4.8=528372+, 4.7.2=461823+, 4.7.1=461320+, 4.6.2=394821+
$netVulnerable = $false
if ($release) {
if ($release -ge 528040 -and $release -lt 528372) { $netVulnerable = $true }
elseif ($release -ge 461808 -and $release -lt 461823) { $netVulnerable = $true }
elseif ($release -ge 461308 -and $release -lt 461320) { $netVulnerable = $true }
elseif ($release -ge 394802 -and $release -lt 394821) { $netVulnerable = $true }
}
# --- SharePoint version check (if installed) ---
$spVulnerable = $false
$spReg = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\*\WSS' -ErrorAction SilentlyContinue
foreach ($sp in $spReg) {
$v = [version]$sp.Version
# SP2019 fix: 16.0.10362.20001 | SP2016: 16.0.4915.1000 | SP2013: 15.0.5197.1000
if ($v.Major -eq 16 -and $v.Minor -eq 0 -and $v.Build -lt 4915) { $spVulnerable = $true }
if ($v.Major -eq 15 -and $v.Minor -eq 0 -and $v.Build -lt 5197) { $spVulnerable = $true }
}
if ($netVulnerable -or $spVulnerable) { $verdict = 'VULNERABLE' }
elseif ($release) { $verdict = 'PATCHED' }
}
catch {
$verdict = 'UNKNOWN'
}
Write-Output $verdict
switch ($verdict) {
'PATCHED' { exit 0 }
'VULNERABLE' { exit 1 }
default { exit 2 }
}
If you remember one thing.
<x:Code> payloads at the WAF today. Full vendor patching (the noisgate remediation SLA for HIGH = ≤180 days) should be compressed to the next change window — there is no excuse for a six-year-old patch gap on a SharePoint farm. Any internet-exposed SharePoint instance is an incident-response engagement, not a vulnerability-management ticket.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.