In the last three days, NVD published seven critical, network-exploitable CVEs affecting WordPress plugins. The most consequential record in the supplied data is CVE-2026-109220, a CVSS 9.8 PHP Object Injection vulnerability in the PDF Invoice for WooCommerce + Drag and Drop Template Builder plugin. All plugin versions through 7.1.1 are affected.
The vulnerability is reachable through the customer_note checkout parameter. Insufficient sanitization allows attacker-controlled input to be entity-decoded and placed into invoice HTML, creating a path for PHP Object Injection. Because this input is associated with a customer checkout workflow, defenders should assume that an internet-accessible WooCommerce site may expose the vulnerable path without administrative access unless the vendor advisory explicitly states otherwise.
Do not limit the response to WooCommerce. The same publication set includes critical issues in a project-management plugin and an Uncanny Toolkit for LearnDash plugin, along with four additional critical WordPress CVEs whose product details were not included in the source summary. Every WordPress estate should be inventoried against all seven identifiers.
Confirmed CVE Set
| CVE | Product or component confirmed in source | Affected versions | CVSS | Defensive priority |
|---|---|---|---|---|
| CVE-2026-109220 | PDF Invoice for WooCommerce + Drag and Drop Template Builder | Through and including 7.1.1 | 9.8 Critical | Immediate patch verification, request logging, and compromise assessment |
| CVE-2026-116512 | Project Manager – AI Powered Project Management, Task Management, Kanban Board & Time Tracker | Not stated in the supplied summary | 9.8 Critical | Identify installations and apply the vendor-listed fix |
| CVE-2026-119096 | Uncanny Toolkit for LearnDash | Not stated in the supplied summary | 9.8 Critical | Prioritize internet-facing LMS sites |
| CVE-2026-118235 | Not stated in the supplied summary | Not stated | Critical; score not stated | Map NVD references to installed plugins before remediation |
| CVE-2026-116557 | Not stated in the supplied summary | Not stated | Critical; score not stated | Map NVD references to installed plugins before remediation |
| CVE-2026-89270 | Not stated in the supplied summary | Not stated | Critical; score not stated | Map NVD references to installed plugins before remediation |
| CVE-2026-103882 | Not stated in the supplied summary | Not stated | Critical; score not stated | Map NVD references to installed plugins before remediation |
NVD publication is not itself proof of exploitation. However, critical WordPress plugin vulnerabilities are routinely weaponized quickly because site ownership, plugin versions, and vulnerable paths can be enumerated at internet scale.
Technical Analysis
CVE-2026-109220 attack surface
The affected component processes the WooCommerce checkout field named customer_note. According to the vulnerability description, the plugin insufficiently sanitizes that field, places it verbatim into invoice HTML, and applies entity decoding. The result is a PHP Object Injection condition.
From a defender's perspective, the relevant chain is:
- A remote client submits a crafted
customer_notevalue through a reachable checkout or order workflow. - The plugin preserves the value without adequate contextual sanitization.
- Entity decoding restores characters needed for a serialized PHP object payload.
- Attacker-controlled data reaches the vulnerable object-handling path while the invoice is generated or rendered.
- PHP instantiates an attacker-selected class. If a usable property-oriented programming, or POP, chain exists in WordPress, WooCommerce, the vulnerable plugin, or another installed component, magic methods can trigger file operations, database operations, or command execution.
A CVSS 9.8 score does not prove that every installation is remotely exploitable to arbitrary code execution. PHP Object Injection impact depends on the classes available in the target process and whether a useful POP chain exists. Treat the vulnerability as potentially high-impact and network-reachable, but do not report confirmed remote code execution unless endpoint or application telemetry proves it.
The supplied record does not clearly state whether authentication is required. Because customer_note is normally customer-supplied checkout data, defenders should prioritize publicly accessible checkout flows and should not assume that WordPress administrator restrictions mitigate the issue.
Exploitation status
The source summary does not report:
- Confirmed active exploitation.
- A public proof of concept.
- Inclusion in the CISA Known Exploited Vulnerabilities catalog.
- A CISA-mandated remediation deadline.
That absence must not be interpreted as evidence that exploitation has not occurred. Retain historical logs and hunt before patching where retention permits. Once public technical details circulate, unpatched WordPress sites are commonly scanned and exploited in bulk.
The other six critical CVEs
The summary confirms CVE-2026-116512 and CVE-2026-119096 as CVSS 9.8 issues, but it truncates the affected version and vulnerability details. It provides no product details for CVE-2026-118235, CVE-2026-116557, CVE-2026-89270, or CVE-2026-103882. Do not infer those details from the plugin names or from unrelated vulnerability history. Use the linked NVD records and their vendor references to map each CVE to an installed plugin slug and version before making firewall, patch, or incident-scope decisions.
Detection & Response
1. Inventory the vulnerable plugin before relying on exploit detection
Search every WordPress root for the plugin readme and confirm the Stable tag or plugin header version. Versions through 7.1.1 are vulnerable. A deactivated plugin may still leave accessible files, uploaded invoices, or application data behind; inventory both active and inactive plugin directories.
Also identify:
- Sites using WooCommerce checkout forms that expose a customer note field.
- Web servers with publicly reachable checkout and invoice-generation endpoints.
- WAF, load balancer, reverse proxy, Apache, Nginx, IIS, and ModSecurity logs.
- Whether request bodies are logged. Standard Apache and Nginx access logs normally do not contain POST bodies, so the absence of
customer_notein an access log is not proof of no attack.
Enable body inspection at a WAF or application firewall where lawful and operationally appropriate. Customer notes may contain personal data, so restrict log access and retention accordingly.
2. Hunt for serialized-object payloads
High-value payload indicators include:
- The parameter name
customer_note. - Serialized PHP syntax such as
O:,a:, ors:followed by a length and delimiter. - URL-encoded forms such as
O%3A,%4F%3A, anda%3A. - HTML-entity forms such as
O:or equivalent hexadecimal entities. - References to
unserializeor__PHP_Incomplete_Class.
The strongest signal is the combination of customer_note and serialized-object grammar. Blocking or alerting on the field name alone will generate unnecessary noise because ordinary customers can submit legitimate notes.
---
title: WooCommerce Customer Note PHP Object Injection Probe
id: 1b6c8d7e-4f5a-4f5c-9b61-260109220001
status: experimental
description: Detects serialized PHP object-injection indicators submitted through the WordPress customer_note parameter associated with CVE-2026-109220. The web log source must retain the URI query or inspected request body.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-109220
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/06/23
tags:
- attack.initial_access
- attack.t1190
logsource:
category: webserver
detection:
selection_parameter:
- 'customer_note'
selection_serialized_payload:
- 'O:'
- 'o:'
- 'a:'
- 's:'
- 'O%3A'
- 'o%3a'
- '%4F%3A'
- '%4f%3a'
- 'a%3A'
- 's%3A'
- 'O:'
- 'o:'
- 'O:'
- '__PHP_Incomplete_Class'
- 'unserialize'
condition: selection_parameter and selection_serialized_payload
falsepositives:
- A legitimate customer manually entering serialized data in a checkout note
- Security scanners and authorized application-security testing
level: high
---
title: PHP-FPM Worker Spawned Shell or Download Utility
id: 93a0a650-6f17-4c1c-b8c0-260109220002
status: experimental
description: Detects a PHP-FPM worker spawning a shell, script interpreter, or download utility. This does not prove exploitation of CVE-2026-109220, but it is a high-value post-exploitation signal on a WordPress host.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-109220
- https://attack.mitre.org/techniques/T1059/004/
author: Security Arsenal
date: 2026/06/23
tags:
- attack.execution
- attack.t1059.004
logsource:
category: process_creation
product: linux
detection:
selection_parent_image:
ParentImage|contains:
- '/php-fpm'
selection_parent_command:
ParentCommandLine|contains:
- 'php-fpm'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/python'
- '/python3'
- '/perl'
- '/curl'
- '/wget'
condition: (selection_parent_image or selection_parent_command) and selection_child
falsepositives:
- Deployment pipelines executing through a PHP-FPM environment
- Custom WooCommerce integrations that intentionally invoke system commands
level: high
The first rule requires a backend mapping that searches normalized request URI, query, or body fields. It will not see a normal checkout POST body in a default Apache or Nginx access log. Deploy it against ModSecurity audit logs, WAF logs, reverse-proxy logs with controlled body capture, or an application-security telemetry source.
Microsoft Sentinel and Defender hunt
The following query assumes Apache, Nginx, CDN, or WAF events are ingested through CEF into CommonSecurityLog. It checks the request URL, message, additional extensions, and a request-payload column when that column exists.
let Lookback = 14d;
let SerializedMarkers = dynamic([
"o%3a",
"%4f%3a",
"a%3a",
"s%3a",
"O:",
"o:",
"O:",
"__php_incomplete_class",
"unserialize",
"base64_decode"
]);
CommonSecurityLog
| where TimeGenerated >= ago(Lookback)
| extend RawLog = tolower(strcat(
coalesce(RequestURL, ""), " ",
coalesce(Message, ""), " ",
coalesce(AdditionalExtensions, ""), " ",
coalesce(tostring(column_ifexists("RequestPayload", "")), "")))
| where RawLog contains "customer_note"
| where RawLog has_any (SerializedMarkers)
or RawLog matches regex @"\b(o|a|s):[0-9]+:"
| summarize Events=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), DistinctDestinations=dcount(DestinationHostName), Samples=make_set(RawLog, 5)
by SourceIP, DestinationHostName, DeviceAction
| order by LastSeen desc
Expand the lookback to the maximum available retention if the plugin was installed before NVD publication. A request accepted by the WAF does not establish successful exploitation. Correlate it with invoice generation, PHP errors, file changes, unexpected child processes, and outbound connections from the web host.
Velociraptor plugin inventory artifact
This VQL locates readme files for the named plugin and returns only records whose stable-tag pattern is numerically no higher than 7.1.1. Adjust the glob roots to match the client environment.
SELECT FullPath,
read_file(filename=FullPath, length=262144) AS Readme
FROM glob(globs=[
"/var/www/**/wp-content/plugins/*/readme.txt",
"/srv/www/**/wp-content/plugins/*/readme.txt",
"/opt/**/wp-content/plugins/*/readme.txt",
"C:/inetpub/wwwroot/**/wp-content/plugins/*/readme.txt"
])
WHERE Readme =~ '(?i)PDF Invoice for WooCommerce'
AND Readme =~ '(?im)^Stable tag:\s*(?:[0-6](?:\.\d+){0,2}|7(?:\.0(?:\.\d+)?|\.1(?:\.[01])?))(?:\s|$)'
A readme that uses trunk, a missing stable tag, or a nonstandard version string requires manual validation against the installed plugin header and vendor changelog. Do not treat absence from this artifact as conclusive if WordPress is installed under another path.
Emergency audit and temporary deactivation
Run the script in audit mode first. Use --disable only after confirming that deactivating invoice generation is an acceptable temporary business control. The script intentionally does not invent a fixed version or perform an unverified update.
#!/usr/bin/env bash
set -euo pipefail
PLUGIN_NAME='PDF Invoice for WooCommerce'
MAX_VULNERABLE='7.1.1'
DISABLE=0
ROOTS=()
for arg in "$@"; do
case "$arg" in
--disable)
DISABLE=1
;;
-h|--help)
echo "Usage: $0 [--disable] [wordpress-root-or-parent ...]"
echo "Audit is the default. --disable requires wp-cli and sudo access."
exit 0
;;
*)
ROOTS+=("$arg")
;;
esac
done
if (( ${#ROOTS[@]} == 0 )); then
ROOTS=(/var/www /srv/www /opt/wordpress /home)
fi
FOUND=0
VULNERABLE=0
while IFS= read -r -d '' README; do
if ! grep -qi "$PLUGIN_NAME" "$README"; then
continue
fi
FOUND=$((FOUND + 1))
VERSION=$(grep -im1 '^Stable tag:' "$README" | sed -E 's/^[^:]*:[[:space:]]*//' | tr -d '\r' | awk '{print $1}')
PLUGIN_DIR=$(dirname "$README")
if [[ -z "$VERSION" ]]; then
printf 'UNKNOWN\t%s\tStable tag is missing\n' "$PLUGIN_DIR"
continue
fi
if [[ ! "$VERSION" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
printf 'MANUAL\t%s\tversion=%s\n' "$PLUGIN_DIR" "$VERSION"
continue
fi
OLDEST=$(printf '%s\n%s\n' "$VERSION" "$MAX_VULNERABLE" | sort -V | head -n1)
if [[ "$OLDEST" == "$VERSION" ]]; then
VULNERABLE=$((VULNERABLE + 1))
printf 'VULNERABLE\t%s\tversion=%s\tCVE-2026-109220\n' "$PLUGIN_DIR" "$VERSION"
if (( DISABLE == 1 )); then
MAIN_PHP=$(find "$PLUGIN_DIR" -maxdepth 1 -type f -name '*.php' | sort | head -n1)
WP_ROOT=$(dirname "$(dirname "$(dirname "$PLUGIN_DIR")")")
if [[ -z "$MAIN_PHP" || ! -f "$WP_ROOT/wp-config.php" ]]; then
printf 'ERROR\t%s\tCould not identify the WordPress root or plugin entry point\n' "$PLUGIN_DIR"
continue
fi
if ! command -v wp >/dev/null 2>&1 || ! command -v sudo >/dev/null 2>&1; then
printf 'ERROR\t%s\twp-cli or sudo is unavailable\n' "$PLUGIN_DIR"
continue
fi
WP_USER="${WP_USER:-www-data}"
PLUGIN_REL="$(basename "$PLUGIN_DIR")/$(basename "$MAIN_PHP")"
sudo -u "$WP_USER" wp --path="$WP_ROOT" plugin deactivate "$PLUGIN_REL" --skip-plugins --skip-themes
printf 'DISABLED\t%s\t%s\n' "$WP_ROOT" "$PLUGIN_REL"
fi
else
printf 'NOT-VULNERABLE-BY-VERSION\t%s\tversion=%s\n' "$PLUGIN_DIR" "$VERSION"
fi
done < <(find "${ROOTS[@]}" -type f -path '*/wp-content/plugins/*/readme.txt' -print0 2>/dev/null)
printf 'SUMMARY\tinstallations=%d\tvulnerable=%d\n' "$FOUND" "$VULNERABLE"
if (( VULNERABLE > 0 && DISABLE == 0 )); then
exit 2
fi
A version above 7.1.1 should still be checked against the vendor changelog. The source establishes 7.1.1 as the last affected version, but it does not identify the fixed release. Do not assume that a particular later version is safe unless the vendor or NVD reference explicitly says it resolves CVE-2026-109220.
Remediation
Immediate actions
- Patch CVE-2026-109220 now. Upgrade the PDF Invoice for WooCommerce + Drag and Drop Template Builder plugin to the vendor release that explicitly states that CVE-2026-109220 is fixed. The supplied NVD summary confirms affected versions through 7.1.1 but does not provide the fixed version number.
- Inventory all WordPress instances. Include production, staging, development, multisite installations, forgotten marketing sites, and customer-hosted environments.
- Map all seven CVEs to installed plugins. Use the NVD links above and their vendor references. Do not guess affected versions from plugin names.
- Apply virtual patching if an update cannot be deployed immediately. Inspect raw, URL-decoded, and HTML-entity-decoded
customer_notevalues. Reject serialized-object grammar resembling(?i)(o|a|s)(:|%3a)[0-9]+(:|%3a)or HTML entities that decode to those delimiters. Do not block the entire customer-note field unless the business can tolerate checkout disruption. - Temporarily deactivate the vulnerable invoice plugin if no verified patch is available. Deactivation is an emergency risk-reduction measure, not a substitute for the vendor update. Confirm the effect on order processing, accounting, and customer communications first.
- Preserve evidence before changing the site. Export web, WAF, PHP, application, authentication, and system logs. Include rotated logs and preserve timestamps in UTC where possible.
- Verify after patching. Re-run the inventory, confirm the installed version and file hashes, and test checkout and invoice generation from a staging environment.
Compromise assessment
If telemetry shows a suspicious customer_note request, investigate the subsequent process and file timeline rather than relying only on the request status code. Review:
- New or modified PHP files under WordPress, especially upload and cache directories.
- Plugin and theme files changed outside a documented deployment window.
- New WordPress administrator accounts or unexpected role changes.
- Unexpected scheduled tasks, cron entries, systemd units, or web-server includes.
- PHP-FPM child processes spawning shells, download utilities, archive tools, or script interpreters.
- Outbound connections from the web host immediately following the request.
- Payment-gateway, SMTP, API, webhook, database, and cloud credentials stored by the site.
If code execution or unauthorized access is confirmed, isolate the host, capture forensic images or snapshots, rotate site and integration secrets, force privileged-account credential resets, and rebuild from known-good code and data when integrity cannot be established. For e-commerce sites, determine whether order PII or payment workflows were accessed; do not assume cardholder data is safe merely because a third-party gateway processed payments.
Prioritization for the full CVE set
Use the following order of operations:
- Internet-facing sites processing orders, accounts, learner data, or project data.
- Plugins confirmed to be affected by a CVSS 9.8 record.
- Sites with checkout, registration, file-upload, LMS, or project-management functionality exposed to unauthenticated users.
- Sites showing suspicious serialized payloads, PHP child processes, or integrity changes.
- Remaining WordPress instances after vendor-version mapping is complete.
WordPress automatic updates alone should not be treated as closure. Many managed deployments pin plugin versions, disable automatic updates, use custom plugin forks, or maintain multiple sites under shared infrastructure. Closure requires a version check, vendor-advisory confirmation, functional testing, and at least a targeted historical log review.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.