Back to Intelligence

CVE-2026-87796: Critical Unauthenticated File Upload in Multi Uploader for Gravity Forms — Detection and Remediation Guide

SA
Security Arsenal Team
September 17, 2026
11 min read

NVD has published CVE-2026-87796, a CVSS 9.8 (Critical) vulnerability in the Multi Uploader for Gravity Forms plugin for WordPress, affecting all versions up to and including 1.1.9. The flaw is an unauthenticated arbitrary file upload rooted in the move_file function, which performs insufficient file type validation during chunked upload handling. Because the attack pathway is network-reachable and requires no authentication, no privileges, and no user interaction, any internet-facing WordPress site running this plugin should be treated as an immediate exploitation target.

Arbitrary file upload in WordPress plugins is one of the most reliably weaponized vulnerability classes we see in incident response. Once an attacker can write an arbitrary file to the webroot, the path to remote code execution — typically via a PHP web shell — is trivially short. If you operate WordPress sites with Gravity Forms and this uploader add-on, treat this as a patch-or-mitigate-today event and initiate retroactive hunting for web shells.

Technical Analysis

Affected Products and Versions

ItemDetail
ProductMulti Uploader for Gravity Forms (WordPress plugin)
Affected versionsAll versions up to and including 1.1.9
PlatformWordPress sites with the plugin installed (typically alongside Gravity Forms)
CVECVE-2026-87796
CVSS9.8 (Critical) — network-attack vector, unauthenticated
Root causeInsufficient file type validation in the move_file function during chunked upload handling
Referencehttps://nvd.nist.gov/vuln/detail/CVE-2026-87796

How the Vulnerability Works (Defender's View)

The vulnerable code path lives in the plugin's chunked upload handler. Chunked uploads split a file into multiple HTTP requests, and each chunk must be reassembled and moved into a final destination. The move_file function performs that final move but fails to adequately validate the resulting file type before writing it to a location on the server's filesystem.

From an attacker's perspective, the chain looks like this:

  1. Identify a WordPress site running Multi Uploader for Gravity Forms ≤ 1.1.9 (plugin fingerprinting via public asset paths is trivial).
  2. Submit a crafted chunked upload containing a PHP payload (web shell). The chunking itself may help bypass file-type checks that only inspect the first chunk or rely on client-supplied metadata.
  3. The move_file function reassembles and writes the payload — for example, into a directory under wp-content/uploads/ that is directly reachable over HTTP.
  4. The attacker requests the uploaded file via GET, executing the PHP payload in the web server context (typically the www-data or equivalent service account).
  5. Post-exploitation: credential harvesting from wp-config.php, database dumping, lateral movement into the hosting environment, SEO spam injection, or ransomware staging.

Exploitation Status

As of publication, NVD describes the vulnerability pathway as network-exploitable and unauthenticated. Vulnerabilities of this exact class in WordPress plugins are historically scanned for and exploited within hours to days of public disclosure, regardless of whether a public PoC exists at disclosure time. There is no confirmed CISA KEV entry at time of writing, but defenders should not wait for KEV inclusion — unauthenticated file upload to RCE in a WordPress plugin is a mass-scanning magnet. Assume active reconnaissance against your perimeter is already underway.

Detection & Response

The highest-fidelity detection opportunities are: (1) web server process writing executable files into upload directories, (2) POST requests to the plugin's upload endpoints from unusual sources, and (3) the web server process spawning child processes — the classic web-shell behavioral signature.

SIGMA Rules

YAML
---
title: Web Server Process Writing Executable File to WordPress Uploads Directory
id: 8b4e2c1a-6f3d-4a5b-9c7e-2d1f0a8b6c4d
status: experimental
description: Detects a web server or PHP process writing a PHP/script file into the WordPress uploads directory, consistent with arbitrary file upload exploitation such as CVE-2026-87796.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-87796
  - https://attack.mitre.org/techniques/T1505/003/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.persistence
  - attack.t1505.003
logsource:
  category: file_event
  product: linux
detection:
  selection_process:
    Image|endswith:
      - '/apache2'
      - '/httpd'
      - '/nginx'
      - '/php-fpm'
      - '/php'
  selection_target:
    TargetFilename|contains: '/wp-content/uploads/'
    TargetFilename|endswith:
      - '.php'
      - '.phtml'
      - '.phar'
      - '.php3'
      - '.php4'
      - '.php5'
      - '.php7'
      - '.pht'
  condition: selection_process and selection_target
falsepositives:
  - Legitimate plugin or theme installation/update performed through the WordPress admin panel
  - Developer deployments to staging paths under uploads (uncommon)
level: high
---
title: Web Server Process Spawning Shell or Command Interpreter (Web Shell Behavior)
id: 3c7a9f2e-1d5b-4e8a-b6c9-0f2a4d8e1b3c
status: experimental
description: Detects web server or PHP-FPM worker processes spawning shells or common post-exploitation tools, a strong indicator of web shell execution following arbitrary file upload (e.g., CVE-2026-87796).
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-87796
  - https://attack.mitre.org/techniques/T1505/003/
  - https://attack.mitre.org/techniques/T1059/004/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.execution
  - attack.t1505.003
  - attack.t1059.004
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/apache2'
      - '/httpd'
      - '/nginx'
      - '/php-fpm'
  selection_child:
    Image|endswith:
      - '/sh'
      - '/bash'
      - '/dash'
      - '/zsh'
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
      - '/netcat'
      - '/python'
      - '/python3'
      - '/perl'
      - '/whoami'
      - '/id'
  condition: selection_parent and selection_child
falsepositives:
  - Rare plugin functionality invoking system commands (e.g., image processing via exec) — investigate parent-child context
level: critical
---
title: Suspicious HTTP POST to Gravity Forms Multi Uploader Endpoint
id: 5e1b8d4c-2a7f-4c3e-8d6a-9b0c3e5f7a2d
status: experimental
description: Detects POST requests to admin-ajax.php carrying Gravity Forms multi-uploader action parameters, potentially indicating chunked upload abuse related to CVE-2026-87796. Tune the action value to your plugin's observed AJAX handler.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-87796
  - https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.initial_access
  - attack.t1190
logsource:
  category: webserver
detection:
  selection_uri:
    cs-uri|contains:
      - '/wp-admin/admin-ajax.php'
      - 'admin-ajax.php'
  selection_method:
    cs-method: 'POST'
  selection_payload:
    cs-body|contains:
      - 'move_file'
      - 'chunk'
      - 'multi_uploader'
      - 'multiuploader'
      - 'gform'
  condition: selection_uri and selection_method and selection_payload
falsepositives:
  - Legitimate form submissions using the multi-uploader field — baseline volume per source IP and flag anomalous spikes or requests from non-user geographies/ASNs
level: medium

KQL (Microsoft Sentinel / Defender)

The following hunts web access logs ingested into Sentinel (via CommonSecurityLog from a WAF/reverse proxy, or custom IIS/Apache log ingestion) for chunked upload attempts against the plugin, and separately hunts endpoint telemetry for web shell drops on Windows-hosted WordPress (IIS).

KQL — Microsoft Sentinel / Defender
// Hunt 1: POST attempts against WordPress AJAX upload endpoints with multi-uploader characteristics
// Adjust table/columns to your log source (CommonSecurityLog for CEF-forwarded WAF/proxy logs)
CommonSecurityLog
| where TimeGenerated > ago(14d)
| where RequestMethod =~ "POST"
| where RequestURL has "admin-ajax.php"
| where AdditionalExtensions has_any ("multi_uploader", "multiuploader", "move_file", "chunk")
    or RequestURL has_any ("multi_uploader", "multiuploader")
| summarize Attempts = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
    by SourceIP, RequestURL, DestinationHostName
| where Attempts > 3 or FirstSeen > ago(72h)
| order by LastSeen desc;

// Hunt 2: Web server worker process creating script files in WordPress uploads (IIS-hosted WordPress on Windows)
DeviceFileEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName in~ ("w3wp.exe", "php-cgi.exe", "php.exe", "httpd.exe")
| where FolderPath has @"\wp-content\uploads\"
| where FileName endswith ".php" or FileName endswith ".phtml" or FileName endswith ".aspx" or FileName endswith ".pht"
| project TimeGenerated, DeviceName, InitiatingProcessFileName, FolderPath, FileName, SHA256, InitiatingProcessAccountName
| order by TimeGenerated desc;

// Hunt 3: Web server process spawning command interpreters (post-exploitation behavior)
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName in~ ("w3wp.exe", "php-cgi.exe", "httpd.exe")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "net.exe", "whoami.exe", "certutil.exe", "curl.exe")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, AccountName
| order by TimeGenerated desc;

Velociraptor VQL

Use this hunt artifact to identify PHP files recently created in WordPress uploads directories across your Linux web tier — the primary artifact left behind by this vulnerability class.

VQL — Velociraptor
-- Hunt for recently created script files inside WordPress uploads directories
-- Indicates possible web shell deployment via arbitrary file upload (CVE-2026-87796)
LET cutoff = time() - 14*24*3600

SELECT FullPath AS FilePath,
       Mtime.Sec AS ModifiedEpoch,
       timestamp(epoch=Mtime.Sec) AS ModifiedTime,
       Size AS FileSize,
       Mode AS Permissions
FROM glob(globs=[
    '/var/www/**/wp-content/uploads/**/*.php',
    '/var/www/**/wp-content/uploads/**/*.phtml',
    '/var/www/**/wp-content/uploads/**/*.pht',
    '/var/www/**/wp-content/uploads/**/*.phar',
    '/srv/www/**/wp-content/uploads/**/*.php',
    '/home/**/public_html/wp-content/uploads/**/*.php'
])
WHERE Mtime.Sec > cutoff
ORDER BY Mtime.Sec DESC

Remediation / Verification Script

Run this on each WordPress host to check plugin version status, enumerate executable files in uploads directories, and apply an immediate hardening control (block PHP execution in uploads) while you patch.

Bash / Shell
#!/bin/bash
# CVE-2026-87796 - Multi Uploader for Gravity Forms verification & hardening
# Run as root or with sudo on the WordPress host

set -u

WP_ROOTS="/var/www /srv/www /home"
echo "=== [1/4] Locating Multi Uploader for Gravity Forms installations ==="
for root in $WP_ROOTS; do
  [ -d "$root" ] || continue
  find "$root" -type d -name "multi-uploader-for-gravity-forms" 2>/dev/null | while read -r plugindir; do
    echo "FOUND plugin directory: $plugindir"
    # Extract plugin version from the main plugin file header
    mainfile=$(grep -rl "Version:" "$plugindir" --include="*.php" 2>/dev/null | head -1)
    if [ -n "$mainfile" ]; then
      ver=$(grep -m1 "Version:" "$mainfile" | awk '{print $NF}')
      echo "  Detected version: $ver"
      # Flag vulnerable versions (1.1.9 and below)
      if printf '%s\n1.1.9\n' "$ver" | sort -V -C; then
        echo "  STATUS: VULNERABLE (<= 1.1.9) - update or deactivate immediately"
      else
        echo "  STATUS: appears patched (> 1.1.9) - verify against vendor advisory"
      fi
    fi
  done
done

echo "=== [2/4] Searching uploads directories for PHP/script files (potential web shells) ==="
for root in $WP_ROOTS; do
  [ -d "$root" ] || continue
  find "$root" -type d -path "*/wp-content/uploads" 2>/dev/null | while read -r updir; do
    hits=$(find "$updir" -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.pht" -o -name "*.phar" \) -mtime -30 2>/dev/null)
    if [ -n "$hits" ]; then
      echo "SUSPICIOUS FILES in $updir (created/modified in last 30 days):"
      echo "$hits" | while read -r f; do ls -la "$f"; done
    fi
  done
done

echo "=== [3/4] Checking for PHP execution blocking in uploads (.htaccess / nginx config) ==="
for root in $WP_ROOTS; do
  [ -d "$root" ] || continue
  find "$root" -type d -path "*/wp-content/uploads" 2>/dev/null | while read -r updir; do
    if [ ! -f "$updir/.htaccess" ]; then
      echo "No .htaccess in $updir - applying Apache hardening"
      cat > "$updir/.htaccess" <<'EOF'
# Block PHP execution in uploads - CVE-2026-87796 mitigation
<FilesMatch "\.(php|phtml|phar|pht|php[0-9])$">
  Require all denied
</FilesMatch>
EOF
      chown --reference="$updir" "$updir/.htaccess" 2>/dev/null || true
      echo "  Wrote $updir/.htaccess"
    else
      echo "  $updir/.htaccess exists - manually verify it blocks PHP execution"
    fi
  done
done

echo "=== [4/4] Reviewing web access logs for suspicious chunked upload POSTs (last 7 days) ==="
for log in /var/log/apache2/access.log /var/log/httpd/access_log /var/log/nginx/access.log; do
  [ -f "$log" ] || continue
  echo "--- $log ---"
  grep -E "POST.*admin-ajax\.php" "$log" 2>/dev/null \
    | grep -iE "multi_uploader|multiuploader|move_file|chunk" \
    | awk '{print $1, $4, $6, $7}' | sort | uniq -c | sort -rn | head -20
done

echo "=== DONE. Patch the plugin via wp-admin or WP-CLI: wp plugin update multi-uploader-for-gravity-forms ==="

Remediation

  1. Update the plugin immediately. Upgrade Multi Uploader for Gravity Forms to the latest available release beyond 1.1.9. Verify the fixed version against the official vendor channel and the WordPress plugin repository before deploying — check the changelog explicitly references the file-upload validation fix. Monitor the NVD entry for updated version data: https://nvd.nist.gov/vuln/detail/CVE-2026-87796.
  2. If no patched version is available yet, deactivate and remove the plugin. With a CVSS 9.8 unauthenticated upload-to-RCE flaw, the residual risk of leaving it active — even behind a WAF — is not defensible. Remove the uploader field from live Gravity Forms and use Gravity Forms' native (patched) file upload field as a temporary substitute.
  3. Block PHP execution in wp-content/uploads/ as a defense-in-depth measure (Apache .htaccess or nginx location block as shown in the script above). This breaks the upload-to-execution chain for this vulnerability class broadly, not just this CVE.
  4. Hunt retroactively. Assume exploitation may predate your patch. Sweep uploads directories for unexpected PHP/script files (see VQL and script above), review web access logs for anomalous POST volume to admin-ajax.php, and inspect the web server account for spawned child processes or outbound connections.
  5. If any web shell artifacts are found, treat it as a full compromise: isolate the host, preserve forensic images, rotate all credentials in wp-config.php (database, salts/keys, admin accounts), audit WordPress user accounts for rogue administrators, and rebuild from a known-clean backup where integrity cannot be assured.
  6. Reduce attack surface going forward: enforce automatic updates for WordPress plugins, inventory all installed plugins across your WordPress estate (a forgotten plugin is an unmanaged vulnerability), and place a WAF rule set with virtual patching capability in front of internet-facing WordPress properties.

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.