-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 NEFARIOUSPLAN-CANONICAL-V1 {"body_md":"## The XSS is real. The PoC is not about the XSS.\n\nCVE-2026-42897 lands in the May 15 OWA security update. The CVSS vector is `AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N`: network attack, no privileges, one click. The mechanism is the textbook OWA-renders-attacker-controlled-HTML shape. An email is composed with a payload that survives OWA's sanitization, the recipient opens it, the script executes in the browser tab that holds an authenticated Exchange session. The Blackpoint Adversary Pursuit Group post on infosec.exchange names the kill chain: session token theft, credential harvesting, lateral pivot from the Exchange box. CISA puts it on the Known Exploited Vulnerabilities list with a May 29 deadline. None of that is novel. Every OWA XSS since 2020 reads like this.\n\nThe public PoC for CVE-2026-42897 was published on GitHub on May 15 by an author who goes by `atiilla`. The repository is named for the CVE. It contains one PowerShell script and a README. Neither file demonstrates the XSS. Neither file builds an exploit email. Neither file touches Exchange's HTML sanitization, OWA's response rendering, or the script-injection sink. The PoC demonstrates a different bug.\n\nThe bug it demonstrates is in Microsoft's own diagnostic tooling. Specifically, in the function the Exchange Health Checker uses to enumerate IIS URL Rewrite rules. The PoC's claim, in one sentence: Microsoft's mitigation for CVE-2026-42897 deploys an IIS rewrite rule into a section of the IIS configuration that Microsoft's verification tool does not read.\n\nThe README rates that bug at CVSS 5.3 and credits the original discovery to whoever filed `microsoft/CSS-Exchange` issue #2539. The author's choice to publish under the headline CVE rather than open a new one is editorial. It is also accurate in the way the author intends. The bug is meaningful only if you know there is a mitigation worth verifying. The XSS gives the mitigation its weight. The mitigation gives the audit tool its purpose. The audit tool gives the admin a reason to believe the server is safe. The chain collapses at the audit tool.\n\n## `Get-URLRewriteRule.ps1` reads `.rewrite.rules` in three places.\n\nThe Health Checker enumerates IIS URL Rewrite configuration by reading three sources, in this order: the application's `web.config`, the per-location entries in `applicationHost.config`, and the global `system.webServer` block in `applicationHost.config`. Each source is parsed independently. Each read targets the same XPath suffix.\n\nFrom `Diagnostics/HealthChecker/Analyzer/Get-URLRewriteRule.ps1` at HEAD on `microsoft/CSS-Exchange`:\n\n```powershell\n# Path 1: web.config (line 47)\n$rules = $content.configuration.'system.webServer'.rewrite.rules\n\n# Path 2: applicationHost.config per-location entry (line 62)\n$rules = $location.'system.webServer'.rewrite.rules\n\n# Path 3: applicationHost.config global system.webServer (line 79)\n$rules = $ApplicationHostConfig.configuration.'system.webServer'.rewrite.rules\n```\n\nThree reads of `.rewrite.rules`. Zero reads of `.rewrite.outboundRules`. The variable that receives each read is named `$rules`, which is what `$rules` is in IIS: the inbound collection. The outbound collection has a different XML name (`outboundRules`) and a different schema. The Health Checker function never touches it.\n\nThe downstream consumer in `Invoke-AnalyzerIISInformation.ps1` iterates `$currentRewriteRules.rule`, the singular subtree under whichever collection was read:\n\n```powershell\n$displayRewriteRules = ($currentRewriteRules.rule |\n Where-Object { $_.enabled -ne \"false\" }).name |\n Where-Object { $_ -notcontains $excludeRules }\n```\n\nFiltering is by `enabled -ne \"false\"`. If a rule is present in the inbound collection, it is reported. If a rule is present in the outbound collection, the loop never sees it. The outbound collection isn't in `$urlRewriteRules` to begin with, because nothing upstream put it there.\n\nThe three read paths exist because IIS stores rewrite configuration in three places, and the Health Checker correctly walks all three. The bug is not that the function missed a path. The function missed a sibling node at every path.\n\n## EOMT deploys to the section Health Checker doesn't read.\n\nThe Exchange On-premises Mitigation Tool is Microsoft's emergency stopgap when a critical bug needs to be neutralized faster than admins can stage a full Cumulative Update. EOMT modules deploy as PowerShell scripts under `Security/src/EOMT/Mitigations/`. They run with admin rights on the Exchange box, edit IIS configuration in place, and leave the server with a narrowed attack surface.\n\nFor CVE-2026-42897, EOMT installs a Content-Security-Policy header on every OWA response. The CSP forbids inline script execution by default, which is the class of attack the XSS enables. The CSP cannot be added by modifying the response in OWA's code path, because the response is rendered by the same vulnerable stack the mitigation is trying to protect. So EOMT installs it at the IIS layer, where rewrite rules can transform the response after Exchange has handed it off.\n\nIIS rewrite rules transform incoming requests through `` and outgoing responses through ``. A CSP response header is, by definition, outgoing. There is no other place an IIS rewrite rule can install a response header. EOMT's mitigation block looks like this:\n\n```xml\n\n \n \n \n \n \n \n\n```\n\nThe rule is named `EOMT OWA CSP - outbound`. The string \"outbound\" is in the rule's display name because the rule lives in `` because there is nowhere else it could live. Every part of the EOMT design forces this placement. The mitigation cannot be inbound. The header is on the response.\n\n`Get-URLRewriteRule.ps1`, three lines deep, has already decided it is not going to look there.\n\n## The report for a mitigated server is identical to the report for an unmitigated one.\n\nRun Health Checker on an Exchange server before EOMT. The IIS section of the report enumerates rewrite rules. The `EOMT OWA CSP - outbound` rule is absent because it has not been deployed. The admin reads \"not detected\" and knows the mitigation is missing.\n\nRun Health Checker on the same Exchange server after EOMT. The IIS section enumerates rewrite rules. The `EOMT OWA CSP - outbound` rule is absent because Health Checker did not look at the section where the rule was deployed. The admin reads \"not detected\" and is told the mitigation is missing.\n\nTwo distinct server states. One report. The admin cannot distinguish the case where they have work to do from the case where the work is already done. The wire format of \"I looked and didn't find it\" is the same as the wire format of \"I didn't look in the place it would be.\" Both render as the same dashboard tile. Both leave the administrator one of two equally bad options: redeploy the mitigation, possibly stacking duplicate rules, or inspect the IIS configuration by hand and bypass the audit tool entirely.\n\nThis is the [Idle Indistinguishable From Broken](/patterns/idle-indistinguishable-from-broken) pattern in its purest form, instantiated not in a polling cron but in an audit report. The pattern's mechanism essay names the return-type design choice that fuses success-without-effect into could-not-determine: when the wire format has no field for \"I did not enumerate this collection,\" every possible read of the report collapses both states into one. The cron version of this pattern is a green checkmark that means \"nothing to do\" and \"I have no idea.\" The Health Checker version is a missing rule entry that means \"the mitigation is absent\" and \"I did not look where the mitigation lives.\" (See [Seventeen Green Checkmarks](/posts/runpaperclip-cve-2026-41679-silent-no-op) for the canonical exhibit; this CVE is the same pattern at a different layer.)\n\nDownstream automation inherits the conflation. Compliance dashboards that parse Health Checker JSON to attest mitigation status will report `EOMT OWA CSP - outbound: NOT DETECTED` for every server in the estate, regardless of whether EOMT ran. SOC playbooks that fire on the absence of the rule will fire on every server, mitigated and unmitigated alike. The KEV deadline pressure compounds the failure. Admins on the May 29 clock will run Health Checker, see \"not detected,\" and assume the mitigation never took. The remediation evidence Microsoft asks for cannot be gathered from the tool Microsoft ships for gathering it.\n\n## Both tools ship from the same Microsoft repository.\n\n`microsoft/CSS-Exchange` is the repository. It hosts the Health Checker. It hosts EOMT. Both modules live under the same top-level directory tree. Both modules are maintained by the same Microsoft engineering organization. Both modules are signed and released through the same CSS-Exchange release cadence.\n\nThe EOMT module for CVE-2026-42897 was written by an engineer who understood that an IIS response header had to be installed via `outboundRules`. The Health Checker function for URL rewrite enumeration was written by an engineer who understood that customer-visible rewrite rules typically live under ``. These two understandings are individually correct. They were never reconciled against each other inside one team's design review.\n\nThere is also a [Security Metric Theater](/patterns/security-metric-theater) layer to this. Health Checker's IIS section is presented to administrators as a comprehensive enumeration of URL Rewrite configuration. The denominator the report claims to cover is \"URL Rewrite rules on this server.\" The numerator the function actually walks is \"inbound URL Rewrite rules at three configuration sources on this server.\" The visible coverage looks total. The omitted set is exactly the set that contains the security control. An admin reading the report has no way to know the denominator was cropped before the count began.\n\nThis is the structural failure. There is no architectural decision document that says \"the audit tool will not enumerate outbound rules\" and there is none that says \"the mitigation will live where the audit tool does not look.\" Both omissions emerged from teams optimizing locally. The audit team optimized for the common case: inbound rules are what admins write. The mitigation team optimized for the only case: a CSP response header can only live in outbound rules. Microsoft is the institution that owns the reconciliation. The reconciliation did not happen.\n\n## The patch is three lines per path.\n\nThe remediation, when it ships, will read `.rewrite.outboundRules` at each of the three paths and iterate `.rule` from both collections in the display layer. The PoC includes the patched logic verbatim. The diff per path is on the order of three lines:\n\n```diff\n- $rules = $content.configuration.'system.webServer'.rewrite.rules\n+ $inbound = $content.configuration.'system.webServer'.rewrite.rules\n+ $outbound = $content.configuration.'system.webServer'.rewrite.outboundRules\n+ $rules = @{ inbound = $inbound; outbound = $outbound }\n```\n\nThree lines, three times, plus a display-layer update that iterates both halves of the hashtable. The fix is mechanical. The bug it fixes was in the code for as long as the function has existed, because the function was never written to enumerate outbound rules. The mitigation that exposes the gap is new. The gap is not.\n\nThe May 29 KEV deadline is for the XSS, not for the audit tool. Health Checker has been blind to outbound rewrite rules across every previous EOMT release that used the same primitive, and across every customer-authored outbound rule the audit tool has ever been pointed at. CVE-2026-42897 is the first time the consequence has KEV pressure and a public PoC at the same time. It is not the first time the consequence has existed.\n\nThe verifier cannot tell a server that needs the mitigation from a server that already has it.\n\nPoC: [atiilla/CVE-2026-42897](https://github.com/atiilla/CVE-2026-42897)","closing_line":"The patch closes this CVE. The audit tool that admins run to confirm the patch never reads where the patch lives.","hook_md":"CVE-2026-42897 is a cross-site scripting bug in Outlook Web Access. Microsoft published it on May 15. CISA added it to KEV the same week with a remediation deadline of May 29. Microsoft's Exchange On-premises Mitigation Tool installs a Content-Security-Policy header on OWA by inserting one IIS rewrite rule named `EOMT OWA CSP - outbound`. Microsoft's Exchange Health Checker is the diagnostic tool administrators run to confirm their server's configuration. The Health Checker's `Get-URLRewriteRule.ps1` reads inbound rewrite rules at three places. It never reads outbound rules. An admin who applies the mitigation correctly and runs Health Checker to verify it will receive a report that does not mention the CSP rule. Both tools ship from `microsoft/CSS-Exchange`.","post_id":288,"slug":"exchange-cve-2026-42897-mitigation-invisible-to-health-checker","title":"CVE-2026-42897: EOMT Deploys to Outbound Rules. Health Checker Reads Inbound.","type":"initial","unreadable_sentence":"The verifier cannot tell a server that needs the mitigation from a server that already has it."} -----BEGIN PGP SIGNATURE----- iHUEARYIAB0WIQRf0htP5+SjynlxywneZjl4jgkQJgUCagds4QAKCRDeZjl4jgkQ Jtr3AP4rKss+fRh7DAnQMdROZvVxedHr4A42TxYOBJhMpDuzVAEA3lqYq5ctFHEX Elv5nbSvbZ1Rwcj0OTVI8Knspl28OwM= =KU5d -----END PGP SIGNATURE-----