CVE-2026-82222 is a critical unauthenticated PHP object injection vulnerability in GiveWP, a WordPress donation and fundraising plugin with over 100,000 installs. All versions up to 4.16.7.1 are affected. The flaw is rated CVSS 10.0 and leads to remote code execution. Udin Chan reported it via Patchstack on 2026-07-28. Version 4.16.7.2 fixes it.
if ( self::containsPhpIncompleteClass( $unserializedData ) ) {
return false; // 4.16.6 returned $data here, re-arming the payload
}The exploit chains three flaws. First, the helper safeUnserialize() in src/Helpers/Utils.php calls unserialize() with allowed_classes set to false. That option does not strip objects. It converts them into __PHP_Incomplete_Class placeholders that keep the original class name and all properties. When such a placeholder is serialized again, PHP re-emits the original bytes, so the payload survives intact.
Second, the donation flow in includes/process-donation.php runs account data through this helper and stores it in the wp_give_sessions table. An attacker plants a serialized gadget in their own last_name field via profile.php. On donation submission the value passes safeUnserialize() and is written to the session table. The next read calls unserialize() without any guard, and the gadget object comes back to life.
Third, the gadget chain combines the bundled TCPDF library with Give\TestData classes. The attacker controls the loadedProviders array property of the deserialized object. When the object is destroyed, TCPDF::__destruct() triggers _destroy(), which calls an undefined method and lands in the magic __call(). That method passes the value straight to call_user_func_array() with no validation. Setting loadedProviders to system executes arbitrary OS commands as the web server user.
The chain needs an account, and GiveWP supplies one. The give_action=user_register handler ignores WordPress's users_can_register option, so anyone can register and receive an auth cookie even when registration is disabled. Version 4.16.6 added a nonce, but logged-out nonces are identical across the site, and the [give_register] shortcode emits one on any public page. An attacker harvests it once and reuses it.
The full attack sequence: register via give_action=user_register, plant the gadget in last_name, fetch a donation nonce with action=give_donation_form_nonce, submit a donation via action=give_process_donation omitting give_last. The server writes the gadget into wp_give_sessions before returning HTTP 500. Any subsequent front-end request with the same cookie triggers unserialization, destruction, and system(). The output is reflected in the HTTP response. On 4.16.5.1 and below a default install suffices. Versions 4.16.6 to 4.16.7.1 narrow the surface but remain exploitable under common conditions such as legacy forms or the Option-Based Form Editor.
Patch 4.16.7.2 breaks the chain at five points. safeUnserialize() now returns false when it detects a __PHP_Incomplete_Class; the earlier 4.16.6 attempt returned the raw string, which re-armed the payload. process-donation.php rejects donations with serialized data in name fields, and the usermeta fallback runs through give_clean(). The three read sinks class-give-session.php, class-give-db-sessions.php and class-give-donor-wall.php now pass allowed_classes set to false explicitly; the donor wall mattered most because the public [give_donor_wall] shortcode was reachable anonymously. ProviderForwarder::__call() now verifies the resolved provider before calling it. Donor and billing name meta pass through sanitize_text_field(). A SanitizeSerializedObjectPayloads migration walks usermeta, give_donormeta, give_donationmeta and give_sessions, replacing nested objects with empty strings to clean payloads planted before the update.
The registration bypass remains unresolved in 4.16.7.2, but with the object injection broken it no longer leads to code execution. Patchstack treats it as a separate access-control issue. Site operators should update immediately, verify the sanitization migration actually ran, check for residual serialized payloads in the four tables, and consider blocking give_action=user_register with a WAF rule if registration is not needed.




Comments
No comments yet — be the first.
Open the discussion
No account or password needed — just enter your e-mail and we’ll send you a one-time sign-in link. First time here? You’re set up automatically.
Your rating will be applied automatically after you sign in.
Check your inbox
We’ve sent a sign-in link to …. Open it on this device — this tab will sign you in automatically.
Nothing arrived? Check your spam folder — and mark the mail as "Not spam" so it lands in your inbox next time.