# A Parser Disagreement Between Two Sanitizers Is the Exploitable Seam ## Claim When two functions sanitize the same value using different parsing rules, an input engineered to satisfy one parser while fooling the other is not an edge case — the disagreement itself, not a missing check, is the vulnerability. <!-- atomicity: 1 idea ✓ --> ## Evidence CVE-2026-64638 (pwn.ai, "XSS2Shell") is a clean instance of this pattern rather than a "missing sanitization" bug. WordPress's failed-login username passes through `sanitize_user()` and `wp_strip_all_tags()` (built on PHP's `strip_tags()`), which lets a tag-like string containing whitespace after the opening `<` survive as plain text. The same value is later passed through `wp_kses_post()`, whose separate parser interprets that same surviving string as permitted HTML. Neither function is wrong about its own contract. The two contracts simply disagree, and the gap between them is where attacker-controlled DOM elements land on the login page. This is structurally different from — and harder to catch than — an omission bug. A code reviewer checking "is this value sanitized?" sees yes twice, by two different named, trusted functions, and moves on. The vulnerability only becomes visible when someone asks the second question: sanitized *the same way*, by both? ## Scope & conditions - **Holds** wherever a value is passed through more than one sanitization or validation function at different pipeline stages, and those functions were not designed together against a shared grammar. - **Strongest** in mature codebases with multiple generations of sanitization helpers (`strip_tags()`-family functions alongside `wp_kses`-family functions is exactly this shape) — the more sanitizer functions a codebase has accumulated, the more pairwise disagreements exist to find. - **Breaks** where a single canonical sanitizer is used consistently for a given value across its entire lifecycle — the seam requires two different interpreters, not just two calls. - Detection requires differential testing (feed both parsers the same adversarial corpus and diff the outputs) rather than auditing either function against its own spec in isolation. ## Links - [[3. Resources/Permanent Notes/Perm · WordPress security is now a supply-chain + dependency risk, not just plugin reviews]] — contrasts: that note is about compromised third-party code; this is a first-party defect in trusted core sanitization logic, showing the "assume plugins are compromised" frame doesn't cover every failure mode. - [[3. Resources/Permanent Notes/Client-Supplied Hints Are Not Security Boundaries]] — applies-in: both notes concern the gap between what a value is treated *as* by different consumers versus what it actually *is*. - [[3. Resources/Permanent Notes/A Safety Control That Cannot See Severity Becomes a Hazard]] — applies-in: the same disclosure covers the escalation path (Application Passwords → plugin upload → PHP execution) as conditional, not universal — severity-blind response to "all versions affected" would over- or under-react depending on which claim it's reacting to. - [[WordPress Hosting Security Stack MOC]] — home for this and related WordPress vulnerability-class notes. ## Source - [[3. Resources/Readwise/Articles/New WordPress Pre-Auth XSS Could Lead to PHP Code Execution - Patch ASAP]] — The Hacker News, reporting pwn.ai's disclosure; CVE-2026-64638, patched WordPress 7.0.3. Note: the discovery-process claims (autonomous multi-agent system, ~4 days, open-source models) are pwn.ai's own self-report and were not independently verified by the outlet — the vulnerability's existence is confirmed by WordPress's CVE and patch; the process story is not.