PoC Archive PoC Archive
CVE-2026-82970 category: web CVSS 10 (CRITICAL)
Unverified

WP Cookie Notice Unauthenticated File Upload RCE (CVE-2026-82970)

Published: 2026-09-03 • Researcher: aprnx

Target software WP Cookie Notice for GDPR, CCPA & ePrivacy Consent (WordPress plugin)
Affected versions through 4.4.1
Status Weaponized
Severity Critical · CVSS 10
CVSS 10.0/10
Severity
Critical
CVE
CVE-2026-82970
Category
web
Affected product
WP Cookie Notice for GDPR, CCPA & ePrivacy Consent (WordPress plugin)
Affected versions
through 4.4.1
Disclosed
2026-09-03
Patch status
Unverified
On this page

Metadata

FieldValue
Date Added2026-09-03
Author / Researcheraprnx
CVE / AdvisoryCVE-2026-82970
Categoryweb
SeverityCritical
CVSS Score10.0
StatusWeaponized
TagsRCE, WordPress, file upload, unauthenticated, PHP, webshell

Affected Target

FieldValue
Software / SystemWP Cookie Notice for GDPR, CCPA & ePrivacy Consent (WordPress plugin)
Versions Affectedthrough 4.4.1
Patched Version4.4.2
Language / PlatformPHP / WordPress
Authentication RequiredNo (unauthenticated)
Network Access RequiredRemote

Summary

CVE-2026-82970 is an unrestricted file upload vulnerability in the WP Cookie Notice for GDPR, CCPA & ePrivacy Consent WordPress plugin. The REST endpoint POST /wp-json/wplp-react-gdpr/v1/upload-logo accepts image_base64 and file_name parameters without authentication or file type validation, allowing an unauthenticated attacker to upload a PHP webshell to the WordPress uploads directory and achieve remote code execution.

Vulnerability Details

Root Cause

The plugin exposes a REST API endpoint for logo uploads that lacks both authentication checks and file extension validation. An attacker can specify any filename including .php and provide arbitrary base64-encoded content.

Attack Vector

  1. Send POST request to /wp-json/wplp-react-gdpr/v1/upload-logo with a base64-encoded PHP shell and a .php filename
  2. The plugin saves the file to the WordPress uploads directory
  3. Access the uploaded shell URL to execute arbitrary commands

Impact

Unauthenticated remote code execution on any WordPress site running the vulnerable plugin version.

References

Notes

Auto-ingested from https://github.com/aprnx/wplp-cookie-consent-rce on 2026-09-03.

scanner.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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python3
"""
Scanner for CVE-2026-82970 – WP Cookie Notice Arbitrary File Upload.
Detects vulnerable WordPress sites by checking for the plugin and REST endpoint.
"""

import argparse
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

REST_ENDPOINT = "/wp-json/wplp-react-gdpr/v1/upload-logo"
PLUGIN_README = "/wp-content/plugins/gdpr-cookie-consent/readme.txt"

def check_plugin_readme(base):
    try:
        r = requests.get(f"{base}{PLUGIN_README}", timeout=8, verify=False)
        if r.status_code == 200:
            text = r.text.lower()
            if "gdpr" in text or "cookie consent" in text:
                return True
    except:
        pass
    return False

def check_rest_endpoint(base):
    try:
        r = requests.get(f"{base}{REST_ENDPOINT}", timeout=8, verify=False)
        # 405/200/403 indicates route exists; 404 means not present
        return r.status_code != 404
    except:
        return False

def scan(target):
    base = target.rstrip('/')
    print(f"[*] {base}")
    plugin = check_plugin_readme(base)
    endpoint = check_rest_endpoint(base)

    if plugin:
        print("    [+] Plugin detected (readme.txt found)")
    else:
        print("    [-] Plugin readme not found")

    if endpoint:
        print(f"    [+] REST endpoint reachable: {REST_ENDPOINT}")
    else:
        print("    [-] REST endpoint not found")
        return False

    if plugin or endpoint:
        print("    [*] Target is likely vulnerable to CVE-2026-82970")
        return True
    else:
        print("    [*] Target does not appear vulnerable")
        return False

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("targets", help="File with one URL per line")
    args = parser.parse_args()

    with open(args.targets) as f:
        targets = [line.strip() for line in f if line.strip()]

    for t in targets:
        scan(t)

if __name__ == "__main__":
    main()