
Nicht authentifizierter reflektierter XSS in WPForms <= 2.0.2.1 — Umgehung der Smart-Tag-Escaping-Maßnahme von CVE-2026-88996 an der Attributnamen-Position
Betroffen: WPForms – AI Form Builder for WordPress (kostenlos/Lite), Version 2.0.2.1 — die zum Zeitpunkt der Offenlegung aktuelle neueste Version (zugleich die Version, die den Fix für CVE-2026-88996 enthält). Die Pro-Edition nutzt denselben Smart-Tag-Renderer.
Klasse: Nicht authentifizierte reflektierte Cross-Site-Scripting-Schwachstelle (CWE-79) mit verifizierter JavaScript- Ausführung, über einen unvollständigen Fix von CVE-2026-88996 / GHSA-8j5g-9vmv-9mmw.
Entdeckt: 2026-09-27 ·
Gemeldet an Patchstack: 2026-09-27 ·
Abgelehnt: 2026-09-28 („das Problem tritt nur auf, wenn der Site-Administrator ein bloßes Smart Tag dort geschrieben hat, wo ein HTML-Attributname hingehört … keine Standardkonfiguration und kein Muster, das jemand realistischerweise erstellen würde“ — technische Validität nicht bestritten) ·
Öffentlich: 2026-09-28.
Der Fix in 2.0.2.1 für die reflektierte XSS aus der CVE-2026-93485-Familie maskiert Smart-Tag-Werte, die
in Markup eingesetzt werden (SmartTags::escape_for_attribute() kodiert Anführungszeichen und
Leerzeichen). Das ist wirksam, wann immer der eingesetzte Wert innerhalb eines in Anführungszeichen gesetzten
Attributwerts landet. Wenn ein Formularautor ein bloßes Smart Tag an einer Attributnamen-
Position in der Bestätigungsnachricht platziert — z. B.:
<input {field_id="3"}>
Ein übermitteltes Feldwert, das keine Anführungszeichen und keinen Leerraum enthält, wie z. B.
onmouseover=alert(1), wird wörtlich eingefügt und wird zu einem neuen, aktiven Event-Handler-
Attribut. Die Escaping-Methode kodiert niemals =, und Attributnamen erfordern weder Anführungszeichen noch
Leerraum. Die an den anonymen Einreicher zurückgegebene Bestätigung enthält dann:
<input onmouseover=alert(1)>
Anonyme Übermittlungen an admin-ajax.php (action=wpforms_submit,
wp_ajax_nopriv_*) sind für abgemeldete Benutzer konstruktionsbedingt nonce-frei, daher
handelt es sich um ein vollständig nicht authentifiziertes reflektiertes XSS. Beliebiges
JavaScript wird innerhalb der Single-Token-Beschränkung über
onmouseover=eval(String.fromCharCode(...)) ausgeführt.
Beim selben Formular wird die Payload-Form der übergeordneten CVE – das Durchbrechen von
Anführungszeichen aus einem in Anführungszeichen gesetzten Wert heraus, z. B.
x" onfocus=alert(1) autofocus y=" – an jeder Position korrekt escaped (beobachtete
"- /  -Kodierung). Das Escaping von 2.0.2.1 funktioniert überall außer bei
der Platzierung im Attributnamen. Dies ist ein unvollständiger Fix derselben
Substitutions-Senke, keine separate Funktionslücke.
# 1. WordPress + WPForms lite 2.0.2.1, create a form with a single-line text field (id 3)
# 2. Set the form's Confirmation message to:
# A: <input value="{field_id="3"}"> B: <input {field_id="3"}>
# 3. Run the PoC (stdlib-only Python 3):
python3 poc.py --url http://target.example/form-page/
Erwartete Ausgabe:
[+] field 3 reflects into the confirmation message
[payload (bypass position)] occurrences: LIVE=1 ESCAPED/INERT=2
LIVE -> ...<input onmouseover=alert(poc93485)>...
[control] parent-CVE payload escaped everywhere: YES (fix works at value positions)
=== VERDICT: VULNERABLE — payload reaches attribute-NAME position unescaped ===
poc.py erkennt automatisch das Formular, die Felder und das reflektierende Feld; sendet anonym ab; und
klassifiziert jedes Vorkommen als LIVE (Attributnamen-Injektion) vs. ESCAPED (quotierter Wert,
die Form der übergeordneten CVE). Exit-Code 0 = anfällig.
Die vom Administrator verfasste Bestätigungsnachricht des Formulars muss einen bloßen, eingabe-reflektierenden Smart Tag innerhalb von Markup an der Attributnamen-Position enthalten. Die Forscher von Patchstack bewerteten dies als ein unrealistisches Autorenmuster; es ist nichtsdestotrotz eine dokumentierte Feature-Position, das Escaping existiert genau dafür, die Substitution im Markup-Kontext sicher zu machen, und der Autor erhält keinen Fehler — nur eine stille Injektion.
Kodiere = im Markup-Kontext-Escaping, oder parse das Bestätigungs-Markup kontextuell
und erlaube die Smart-Tag-Substitution nur an Text- und quotierten Attributwert-Positionen.
poc.py — eigenständiger PoC (keine serverseitigen Schritte, keine Abhängigkeiten)poc.sh — minimale curl-basierte VarianteNur für autorisierte Tests und Bildungszwecke. Der Melder veröffentlicht dies, nachdem ein Versuch einer koordinierten Einreichung abgelehnt wurde; der technische Befund wurde nicht bestritten.
Ashish Kunwar (@D0rkerdevil)