Overview
A critical PHP Object Injection vulnerability, tracked as CVE-2026-104736, has been disclosed in LearnPress – WordPress LMS Plugin, developed by ThimPress and used to run online courses on WordPress. The flaw carries a CVSS 3.1 score of 9.8 and affects all versions through 4.4.10. It is exploitable by unauthenticated attackers and a public proof-of-concept is reportedly already circulating.
The bug lives in the checkout AJAX action: the checkout-email request parameter is stored and later fed straight into PHP's unserialize() without restricting which classes can be instantiated, giving an attacker a path to inject arbitrary PHP objects — and, if a suitable gadget chain exists in LearnPress or its dependencies, remote code execution.
Technical Details
| Field | Value |
|---|---|
| CVE ID | CVE-2026-104736 |
| CVSS 3.1 Score | 9.8 (Critical) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-502 — Deserialization of Untrusted Data |
| Attack Vector | Network |
| Authentication | None required |
| Privileges Required | None |
| User Interaction | None |
| Affected Parameter | checkout-email (Checkout AJAX action) |
| Vulnerable Path | LP_Session_Handler::get() → LP_Helper::maybe_unserialize() → unserialize() (no allowed_classes restriction) |
| Affected Versions | LearnPress, all versions through 4.4.10 |
| Assigner | Wordfence |
| Reserved / Disclosed / Published | 2026-10-02 / 2026-10-16 / 2026-10-17 |
| Exploit Status | Public PoC reportedly available; not yet listed in CISA KEV |
How It Works
When a shopper checks out of a LearnPress course, the plugin's AJAX checkout handler accepts a checkout-email value and runs it through WordPress's sanitize_text_field() before storing it in the LearnPress session table. That function strips HTML tags and special characters, but it was never designed to neutralize serialized PHP object syntax — so a crafted serialized payload passes through untouched.
On a later request, LP_Session_Handler::get() retrieves that stored value and passes it to LP_Helper::maybe_unserialize(), which calls PHP's native unserialize() with no allowed_classes restriction. Because the attacker fully controls the byte string being deserialized, they can instantiate arbitrary PHP objects defined anywhere in LearnPress's codebase or its loaded dependencies. Whether that escalates to full remote code execution depends on whether a usable "gadget chain" (a sequence of magic methods like __wakeup or __destruct that perform dangerous actions) exists in the loaded class set — a condition PHP object injection bugs in large plugins frequently satisfy.
No authentication or prior interaction is required: the checkout flow is reachable by any site visitor, making this a fully unauthenticated, remotely exploitable issue.
Impact Assessment
| Impact Area | Description |
|---|---|
| Confidentiality | High — depending on the gadget chain, can expose arbitrary site and database data |
| Integrity | High — can lead to arbitrary file writes or code execution if a gadget chain is present |
| Availability | High — malicious objects can trigger destructive side effects on deserialization |
| Authentication Required | None |
| Automatable | Yes — a single crafted HTTP POST to the checkout AJAX action is sufficient to attempt exploitation |
Who Is At Risk
- Any WordPress site running LearnPress through version 4.4.10 to sell or deliver online courses
- Sites with a large footprint of third-party plugins, which widen the pool of classes an attacker could target for a gadget chain
- Given a public PoC is reportedly circulating, exposure risk should be treated as immediate, not theoretical
Attack Chain
- Crafted request — Attacker sends an HTTP request to the LearnPress checkout AJAX action with a serialized PHP object payload in the
checkout-emailfield. - Sanitization bypass —
sanitize_text_field()strips HTML but leaves the serialized object syntax intact; the value is persisted to the session table. - Unsafe deserialization — A subsequent request triggers
LP_Session_Handler::get(), which callsunserialize()on the stored value with no class allowlist. - Object instantiation / gadget chain — If a usable magic-method chain exists in the codebase, the attacker achieves file writes, data exposure, or remote code execution.
Mitigation
Immediate Actions
- Update LearnPress to the patched release referenced in the plugin's WordPress SVN changeset as soon as it is available on your site's update channel — do not delay given the unauthenticated, no-interaction attack path and reported public PoC.
- Until patched, consider temporarily disabling or restricting access to the LearnPress checkout AJAX endpoint via your WAF if the course catalog can tolerate a short checkout outage.
Detection Opportunities
- Inspect access and application logs for checkout AJAX requests where
checkout-emailcontains serialization markers such asO:,a:, ors:followed by digits and colons — these are not valid email addresses and indicate an injection attempt. - Watch for anomalous PHP errors or warnings referencing
unserialize()or unexpected class names around the time of suspicious checkout requests.
Defence-in-Depth
- Run PHP with
disable_functionshardening where feasible, and keep server-level PHP and WordPress core patched to reduce the pool of exploitable gadget chains. - Apply least-privilege database and file-system permissions to the web server user so a successful object-injection chain has a smaller blast radius.
- Audit installed plugins for classes with dangerous
__wakeup,__destruct, or__toStringimplementations, which are the building blocks of PHP object injection exploitation.
Background
LearnPress is a widely deployed Learning Management System (LMS) plugin for WordPress from ThimPress, used by schools, training businesses, and course creators to sell and deliver online courses directly through WordPress. Because its checkout flow is, by design, reachable by anonymous visitors, any deserialization flaw in that path carries an unusually direct line from "unauthenticated visitor" to "server-side code execution."