---
title: "GiveWP Vulnerability Weaponizes Its Own Bundled Code for RCE"
slug: "givewp-php-object-injection-rce-cve-2026-82222"
description: "CVE-2026-82222 chains GiveWP's own TCPDF library and a broken safeUnserialize() into RCE. See how the GiveWP vulnerability works and how to patch it."
date: 2026-09-14
author: "WP Vanguard Team"
category: "Research"
tags: ["givewp-vulnerability", "cve-2026-82222", "php-object-injection", "remote-code-execution", "gadget-chain"]
featured_image: "/images/blog/givewp-php-object-injection-rce-cve-2026-82222.jpg"
---

GiveWP shipped version 4.16.7.2 on August 27, 2026, one day before the world learned why the update mattered. The GiveWP vulnerability behind that release, tracked as CVE-2026-82222, lets an attacker with no account and no special access run operating system commands on unpatched sites, and more than 100,000 sites run the plugin. Patchstack, which published the research, rates it CVSS 10.0. Wordfence's own advisory lists it at 9.8. Either number sits at the top of the scale, and the mechanism behind it deserves more attention than a scary score alone gives it.

## What's Affected and Who's Exposed

GiveWP is a donation and fundraising plugin built by StellarWP, a Liquid Web company, installed on more than 100,000 WordPress sites according to the WordPress.org plugin directory. Every version through 4.16.7.1 carries the flaw. On 4.16.5.1 and earlier, a published donation form with an active payment gateway is enough. Versions 4.16.6 through 4.16.7.1 also need a legacy or option-based donation form, which the version breakdown below covers.

Because GiveWP processes payment data and stores donor records, a server compromise here reaches further than a defaced page. An attacker who reaches command execution can read `wp-config.php` and harvest gateway API keys, then pivot into whatever else the web server user can touch.

## How the Object Injection Chain Works

The attack takes about four separate requests, not one. Patchstack's technical writeup breaks it down step by step, and it's worth following closely because nothing in it needs a file written to disk or a third-party library beyond what GiveWP already ships.

First, the attacker hits GiveWP's own registration handler with `give_action=user_register`. That endpoint creates a WordPress account regardless of whether the site has open registration turned on, and it needs no login to reach.

Second, logged into that new account, the attacker edits their profile and stores a serialized PHP object in the `last_name` field.

Third, the attacker submits a donation without the normal `give_last` parameter. That code path reads the attacker's `last_name` value back out of the users table and runs it through GiveWP's `maybeSafeUnserialize()` helper, then stores the result in the `wp_give_sessions` table.

Fourth, a later request to any front-end page deserializes that session data again, this time without the guard that protected the first read, and the gadget chain fires.

## Why allowed_classes => false Didn't Stop It

GiveWP's `safeUnserialize()` function calls PHP's native `unserialize()` with `['allowed_classes' => false]`. On paper that's a real mitigation. PHP refuses to instantiate the attacker's chosen class and hands back a generic `__PHP_Incomplete_Class` object instead, one that shouldn't be able to run any code at all.

The gap is what happens next. Per Patchstack's analysis, a `__PHP_Incomplete_Class` object still remembers its original class name and property values. When GiveWP re-serializes that object to store it in the sessions table, PHP writes the original class name straight back into the string, not a placeholder. The safety net applied at read time, and only once. The payload comes out the other side exactly as dangerous as it went in, sitting in `wp_give_sessions` until the next deserialization that doesn't carry the same restriction.

That second read has no restriction, and it's where the gadget chain runs. The chain starts inside TCPDF, a PDF library GiveWP bundles to generate donation receipts. `TCPDF::__destruct()` fires automatically the moment PHP's garbage collector cleans up the deserialized object, no further attacker action required. From there the chain passes through classes GiveWP ships under `Give\TestData` on its way to a trait called `ProviderForwarder`. That trait defines a `__call()` magic method that hands its arguments straight to `call_user_func_array()`. Point that call at `system()`, and PHP object injection becomes a shell command running as the web server user.

Every piece of this chain, TCPDF, `Give\TestData`, and `ProviderForwarder`, ships inside the give plugin's own folder. The attacker doesn't need a gadget chain borrowed from some other plugin or a development library that leaked into production. GiveWP hands them the whole toolkit already installed.

## Version-Specific Exploitability

| Version range | What's required |
|---|---|
| 4.16.5.1 and earlier | One published donation form and an active gateway. GiveWP enables the manual (Test Donation) and offline gateways by default, so most default installs already qualify. |
| 4.16.6 through 4.16.7.1 | The same chain, plus a publicly obtainable registration nonce and a legacy Visual Form Builder (v3) form, or one using the Option-Based Form Editor. WordPress issues the same nonce to every anonymous visitor, so an attacker reads one straight off the site's own donation page. |
| 4.16.7.2 and later | Fixed. |

Either band is exploitable without an account and without any interaction from a real visitor or admin.

## What 4.16.7.2 Changed

StellarWP didn't patch a single line here. The update closes five separate points in the chain.

- Donation submissions get rejected outright when a name field contains serialized data, and every donor and billing name field now runs through `sanitize_text_field()` before storage.
- Three separate `unserialize()` calls, in the session getter, the raw session table read, and the donor wall shortcode, now enforce `allowed_classes => false` in a way that also blocks the re-serialization trick described above.
- `ProviderForwarder::__call()` now validates the provider it's about to invoke before handing it to `call_user_func_array()`.
- A migration named `SanitizeSerializedObjectPayloads` runs on update and scans `usermeta`, `give_donormeta`, `give_donationmeta`, and `give_sessions` for existing objects, replacing them with empty strings.

That last point matters more than it looks. Most plugin security patches close the door going forward and leave whatever already got through for you to find on your own. This one also sweeps the floor behind it. If you update to 4.16.7.2 or later and the migration runs cleanly, there's no staged payload left waiting in those four tables for a future donation to wake it up.

## How to Check and Patch

No public tracking source, including OpenCVE, currently lists this GiveWP vulnerability as exploited in the wild. That's the good news. The bad news is that proof-of-concept exploit code for the full chain is already public, and a published PoC historically shortens the runway to real attacks. Patch on the assumption that scanning starts soon, not on the assumption that it hasn't started yet.

Update the plugin first:

```bash
wp plugin update give
```

Confirm the installed version:

```bash
wp plugin get give --field=version
```

Anything below 4.16.7.2 is still vulnerable. If you can't update immediately, deactivating GiveWP removes every code path this bug depends on:

```bash
wp plugin deactivate give
```

Check for accounts you don't recognize, since account creation is the first step of the whole chain:

```bash
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
```

Look for anything registered through GiveWP's own handler rather than your normal signup flow, and for accounts that appeared around donation activity that doesn't match a real donor.

If you ran an older version for any length of time before updating, don't treat the migration alone as closing the incident. Object injection that reaches `system()` is a full server compromise, not a WordPress-only problem. Run a scan for modified files, unfamiliar cron jobs, and other backdoor indicators a database migration can't clean up. [Run a scan on your site](/#scanner) and treat any unexplained finding as a compromise until you can rule it out.

This bug belongs to a pattern we've written about before: unsafe deserialization sitting inside a plugin's own code, not a forgotten third-party dependency. Our [breakdown of PHP object injection across WordPress plugins](/blog/php-object-injection-wordpress-plugins) covers how common this bug class has gotten and what to check for in code you maintain yourself. If you find evidence the server was actually compromised before you patched, our [WordPress malware removal guide](/blog/wordpress-malware-removal-guide) walks through what a real cleanup requires, and our [checklist for signs a WordPress site has been hacked](/blog/signs-wordpress-site-hacked) is worth running even when nothing looks wrong yet.

## References

- [Patchstack: Unauthenticated PHP Object Injection to Remote Code Execution on GiveWP](https://patchstack.com/articles/unauthenticated-php-object-injection-to-remote-code-execution-on-givewp/)
- [Patchstack Database: WordPress GiveWP Plugin <= 4.16.7.1 - Remote Code Execution (RCE) Vulnerability](https://patchstack.com/database/wordpress/plugin/give/vulnerability/wordpress-givewp-plugin-4-16-7-1-remote-code-execution-rce-vulnerability)
- [BleepingComputer: GiveWP WordPress donation plugin flaw lets hackers execute server commands](https://www.bleepingcomputer.com/news/security/givewp-wordpress-donation-plugin-flaw-lets-hackers-execute-server-commands/)
- [OpenCVE: CVE-2026-82222](https://app.opencve.io/cve/CVE-2026-82222)
- [The Hacker News: Five Critical WordPress Plugin and Theme Flaws Enable Site Takeover or RCE](https://thehackernews.com/2026/08/five-critical-wordpress-plugin-and.html)
