PoC Archive PoC Archive
Critical CVE-2025-22777 patched

GiveWP Unauthenticated PHP Object Injection via Weak Serialized-Data Regex Check (CVE-2025-22777)

by SevDMG · 2026-07-06

CVSS 9.8/10
Severity
Critical
CVE
CVE-2025-22777
Category
web
Affected product
GiveWP – Donation Plugin and Fundraising Platform (WordPress plugin, 100,000+ active installs)
Affected versions
<= 3.19.3 (patched in 3.19.4)
Disclosed
2026-07-06
Patch status
patched

Metadata

FieldValue
Date Added2026-07-06
Last Updated2026-07-06
Author / ResearcherSevDMG
CVE / AdvisoryCVE-2025-22777
Categoryweb
SeverityCritical
CVSS Score9.8 (per NVD)
StatusPoC
Tagsgivewp, wordpress, wordpress-plugin, php-object-injection, deserialization, unserialize, gadget-chain, cwe-502, php, unauthenticated
RelatedN/A

Affected Target

FieldValue
Software / SystemGiveWP – Donation Plugin and Fundraising Platform (WordPress plugin, 100,000+ active installs)
Versions Affected<= 3.19.3 (patched in 3.19.4)
Language / PlatformPHP (target plugin), Python (PoC/exploit tooling) on WordPress
Authentication RequiredNo
Network Access RequiredYes (HTTP access to the donation form / admin-ajax.php endpoint)

Summary

CVE-2025-22777 is an unauthenticated PHP Object Injection (CWE-502, Deserialization of Untrusted Data) vulnerability in the GiveWP WordPress donation plugin. GiveWP stores certain donor-supplied form field values as serialized PHP meta in the database and runs a regex check meant to confirm the value “looks like” a safe serialized string before it is later passed to PHP’s unserialize(); that regex check is weak and can be defeated by padding the payload with junk/gibberish characters, letting a crafted serialized object slip through and get deserialized. If a suitable gadget chain (a class with an exploitable magic method such as __destruct()/__wakeup()) is reachable in GiveWP or a co-installed plugin/theme, this results in arbitrary PHP object instantiation and potentially remote code execution, arbitrary file write/deletion, or other high-impact side effects — with no authentication required. This mirrored repository is an independent researcher’s work-in-progress PoC that builds a serialized “gadget” object (a FinalGadget/ChainGadget class chain targeting a filename property, injected via the donation form’s give_company field to admin-ajax.php?action=give_process_donation), but the actual HTTP exploit driver (exploit_cve2025-22777.py) ships with an empty payload = {} and no request is ever sent, and the more developed exploit_struct.py script’s exploit() function is truncated before it issues any HTTP request. As shipped, neither script performs a working end-to-end attack.


Vulnerability Details

Root Cause

GiveWP accepts certain donation-form fields (e.g. company name) and persists them as PHP-serialized donor meta. Before this data is later unserialized, the plugin performs a regex-based sanity check intended to reject anything that isn’t a “clean” serialized string. That regex is not strict enough: an attacker can interleave arbitrary junk bytes around/within a valid serialized-object payload, and the check still passes, so the tainted string reaches PHP’s unserialize() call path. This class of bug is a textbook CWE-502 (deserialization of untrusted data) — the fix in 3.19.4 tightens the validation so crafted/augmented serialized strings are rejected.

The PoC in this repo models this by hand-crafting a serialized gadget object and further “tweaking” its internal representation to bypass exactly this kind of loose validation, e.g. in test2_phpserializer.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class FinalGadget(phpserialize.phpobject):
    def __init__(self, filename):
        self.filename = filename  # replaces the prop on the givewp repo

def build_payload(filename, verbose=False):
    mal_obj = FinalGadget(filename=filename)
    # Tweaking bypass
    mal_obj.__php_vars__ = b'\xf0\xf0\x09\xbc' + b'FinalGadget'
    payload_serial = dumps(mal_obj)
    encoded_payload = urllib.parse.quote(payload_serial)
    return encoded_payload

The intended injection point is the donation form’s give_company parameter, submitted to WordPress admin-ajax.php with action=give_process_donation:

1
2
3
4
5
6
7
8
data = {
    "give_first" : "sev",
    "give_last" : "test",
    "give_email" : "sev@burner_email.com",
    "give_amount" : "1",
    "give_company" : encoded_payload,  # main injection point
    "action": "give_process_donation"
}

Attack Vector

  1. Attacker locates a WordPress site running a vulnerable GiveWP version (<= 3.19.3) with a public donation form.
  2. Attacker crafts a malicious serialized PHP object (a “gadget”) targeting a class with an exploitable magic method reachable via GiveWP or another installed plugin/theme.
  3. Attacker submits the donation form (directly or via the admin-ajax.php give_process_donation action) with the serialized payload placed in a field such as give_company, padded with extra bytes so the weak validation regex still accepts it as “safe” serialized data.
  4. GiveWP stores this value as donor meta and later calls unserialize() on it without authentication being required at any point.
  5. If a usable gadget chain is present, the deserialization triggers the gadget’s magic method, leading to code execution, file write/deletion, or other object-injection-driven impact.

Impact

Full unauthenticated PHP Object Injection on any public-facing GiveWP donation form; depending on available gadget chains on the target site (GiveWP itself, other plugins, or the theme), this can escalate to remote code execution, arbitrary file read/write/delete, privilege escalation, or site takeover — all without any prior authentication, on a plugin with 100,000+ active installs.


Environment / Lab Setup

- WordPress install with GiveWP plugin <= 3.19.3 (vulnerable) — e.g. via a local WP dev environment (wp-env, LocalWP, Docker WordPress image) with GiveWP installed and a public donation form configured.
- Attacker host: Python 3.x with the packages in requirements.txt:
    phpserialize==1.3
    colorama==0.4.6
    requests==2.32.5
    faker>=25.0.0
- Optional: Burp Suite / proxy for request interception (exploit_struct.py accepts a --proxy argument).

Proof of Concept

PoC Script

See exploit_cve2025-22777.py, exploit_struct.py, test1_with_no_phpserialize.py, test2_phpserializer.py, and test_colorama.py in this folder.

1
2
3
4
5
6
7
8
git clone <repoMainBranchURL>
python -m venv exploitvenv
source exploitvenv/bin/activate
pip install -r requirements.txt

/usr/bin/python3 test2_phpserializer.py

python3 exploit_struct.py --url http://TARGET/wp-admin/admin-ajax.php --file /tmp/poc.txt

Detection & Indicators of Compromise

- POST requests to /wp-admin/admin-ajax.php with action=give_process_donation where donor fields
  (give_company, give_first, give_last, etc.) contain PHP serialization markers (e.g. O:<len>:"ClassName",
  s:<len>:, a:<len>:{) or unusual non-printable/binary byte sequences padding a serialized-looking string.
- Donor/meta database rows (givewp donor meta tables) containing serialized values with embedded
  non-ASCII/control-byte padding around otherwise well-formed PHP serialization syntax.
- Unexpected PHP errors/warnings referencing unserialize() or __wakeup()/__destruct() around donation
  submission timestamps.

Signs of compromise:

  • Anomalous donation submissions with non-standard characters in the company/name fields.
  • New or modified files on the webserver following a donation submission (indicative of a file-write gadget).
  • PHP error logs showing failed unserialize() calls or object instantiation of unexpected classes.
  • Unexpected outbound connections or new admin users appearing shortly after suspicious donation activity.

Remediation

ActionDetail
Primary fixUpdate GiveWP to version 3.19.4 or later, which tightens the serialized-data validation to prevent the regex bypass.
Interim mitigationIf upgrading is not immediately possible: disable/restrict the public donation form, add a WAF rule blocking requests to admin-ajax.php (action=give_process_donation) containing PHP serialization markers (O:, a:, s: patterns) in form fields, and monitor donor meta for anomalous serialized content.

References


Notes

Mirrored from https://github.com/SevDMG/CVE-2025-22777-GiveWP-Plugin-PHP-Object-Injection-Point-PoC- on 2026-07-06. The repository is explicitly marked by its author as a work-in-progress PoC: exploit_cve2025-22777.py ships with an empty payload = {} and never actually sends a functional request, and exploit_struct.py’s exploit() function is truncated before any HTTP request is issued (no session.post(...) call, no CLI argument wiring via argparse). The gadget-building/serialization logic (test2_phpserializer.py) is genuine and illustrates the real bypass technique (padding a serialized object with junk bytes to slip past GiveWP’s weak validation regex), but there is no complete, runnable end-to-end exploit in this repo as of the mirrored commit. Treat this as a conceptual/educational reference for the vulnerability mechanism rather than a functional weaponized exploit.

exploit_cve2025-22777.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#! /usr/bin/env python3
import requests
import argparse
from phpserialize import *
import sys
import os
import colorama
import faker

#same as exploit_struct.py
MAIN_DOMAIN = "vulnerableMainDomain"


session = requests.Session
cookies = session.cookies

payload = {
    
}

session.get(url = f"{MAIN_DOMAIN}/wp-admin/wp-ajax.php", cookies= cookies, data= payload)


if __name__ == '__main__':
    pass