CVE-2026-82222 ist eine kritische PHP-Object-Injection-Lücke ohne Authentifizierung in GiveWP, einem WordPress-Spendenplugin mit über 100.000 Installationen. Alle Versionen bis 4.16.7.1 sind betroffen. Die Lücke ist mit CVSS 10.0 bewertet und führt zu Remote Code Execution. Udin Chan meldete sie am 28.07.2026 über Patchstack. Version 4.16.7.2 schließt sie.

src/Helpers/Utils.php
if ( self::containsPhpIncompleteClass( $unserializedData ) ) {
    return false; // 4.16.6 returned $data here, re-arming the payload
}

Der Exploit verkettet drei Schwächen. Erstens ruft der Helper safeUnserialize() in src/Helpers/Utils.php unserialize() mit allowed_classes auf false auf. Diese Option entfernt Objekte nicht. Sie wandelt sie in __PHP_Incomplete_Class-Platzhalter um, die Klassenname und alle Eigenschaften behalten. Wird ein solcher Platzhalter erneut serialisiert, gibt PHP die Original-Bytes wieder aus. Die Nutzlast überlebt also unverändert.

Zweitens verarbeitet der Spendenvorgang in includes/process-donation.php Accountdaten mit diesem Helper und speichert sie in der Tabelle wp_give_sessions. Der Angreifer hinterlegt ein serialisiertes Gadget im eigenen last_name-Feld über profile.php. Beim Absenden der Spende läuft der Wert durch safeUnserialize() und landet in der Session-Tabelle. Der nächste Lesezugriff ruft unserialize() ohne Schutz auf, und das Gadget-Objekt erwacht wieder zum Leben.

Drittens kombiniert die Gadget-Chain die mitgelieferte TCPDF-Bibliothek mit Give\TestData-Klassen. Der Angreifer kontrolliert die Array-Eigenschaft loadedProviders des deserialisierten Objekts. Bei der Zerstörung des Objekts löst TCPDF::__destruct() _destroy() aus, das eine undefinierte Methode aufruft und in der magischen Methode __call() landet. Diese reicht den Wert ohne Prüfung an call_user_func_array() weiter. Setzt man loadedProviders auf system, werden beliebige Betriebssystembefehle mit den Rechten des Webserver-Benutzers ausgeführt.

Die Kette braucht ein Konto, und GiveWP liefert es frei Haus. Der Handler give_action=user_register ignoriert die WordPress-Option users_can_register. Jeder kann sich registrieren und erhält ein Auth-Cookie, selbst wenn die Registrierung deaktiviert ist. Version 4.16.6 führte ein Nonce ein, doch Nonces für abgemeldete Besucher sind seitenweit identisch, und der Shortcode [give_register] gibt eines auf jeder öffentlichen Seite aus. Einmal ernten, beliebig oft wiederverwenden.

Die komplette Angriffssequenz: Registrierung über give_action=user_register, Gadget in last_name hinterlegen, Spenden-Nonce mit action=give_donation_form_nonce holen, Spende über action=give_process_donation absenden und dabei give_last weglassen. Der Server schreibt das Gadget in wp_give_sessions, bevor er HTTP 500 zurückgibt. Jeder weitere Frontend-Aufruf mit demselben Cookie löst Deserialisierung, Destruktor und system() aus. Die Ausgabe erscheint in der HTTP-Antwort. Bis 4.16.5.1 genügt eine Standardinstallation. Versionen 4.16.6 bis 4.16.7.1 verengen die Angriffsfläche, bleiben aber unter üblichen Bedingungen wie Legacy-Formularen oder dem Option-Based Form Editor verwundbar.

Patch 4.16.7.2 durchbricht die Kette an fünf Stellen. safeUnserialize() gibt bei Erkennung einer __PHP_Incomplete_Class nun false zurück; der frühere Versuch in 4.16.6 gab den Rohstring zurück und rüstete die Nutzlast damit neu. process-donation.php lehnt Spenden mit serialisierten Daten in Namensfeldern ab, und der Usermeta-Fallback läuft durch give_clean(). Die drei Lesesenken class-give-session.php, class-give-db-sessions.php und class-give-donor-wall.php übergeben nun explizit allowed_classes auf false; die Donor Wall war am kritischsten, weil der öffentliche Shortcode [give_donor_wall] anonym erreichbar war. ProviderForwarder::__call() prüft den aufgelösten Provider nun vor dem Aufruf. Donor- und Billing-Namensmeta laufen durch sanitize_text_field(). Eine Migration namens SanitizeSerializedObjectPayloads durchsucht usermeta, give_donormeta, give_donationmeta und give_sessions und ersetzt verschachtelte Objekte durch leere Strings, um vor dem Update platzierte Nutzlasten zu beseitigen.

Der Registrierungs-Bypass bleibt in 4.16.7.2 offen, führt aber ohne die Object Injection nicht mehr zur Codeausführung. Patchstack behandelt ihn als separates Access-Control-Problem. Betreiber sollten sofort aktualisieren, prüfen, ob die Sanitization-Migration tatsächlich lief, die vier Tabellen auf Rest-Nutzlasten kontrollieren und give_action=user_register gegebenenfalls per WAF-Regel blockieren.