Skip to content

CVE-2026-8441: Verified Repro With Script Download

CVE-2026-8441: WP Review Slider Pro SQL injection

CVE-2026-8441 is verified against the affected target. Vulnerability class: SQLi. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00239.

REPRO-2026-00239 SQLi Variant found Jul 6, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.5
Confidence
HIGH
Reproduced in
42m 0s
Tool calls
309
Spend
$15.94
01 · Overview

What Is CVE-2026-8441?

CVE-2026-8441 is a high-severity, unauthenticated SQL injection vulnerability in the WP Review Slider Pro WordPress plugin, reachable via the 'noti' (notinstring) parameter. Pruva reproduced it (reproduction REPRO-2026-00239).

02 · Severity & CVSS

CVE-2026-8441 Severity & CVSS Score

CVE-2026-8441 is rated high severity, with a CVSS base score of 7.5 out of 10.

HIGH threat level
7.5 / 10 CVSS base
Weakness CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

High — serious impact or readily exploitable. Prioritize remediation.

How to Reproduce CVE-2026-8441

$ pruva-verify REPRO-2026-00239
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00239/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-8441

Information disclosure — reproduced
  • reached the target end-to-end
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

HTTP POST field notinstring (ticket abbreviation: noti) in wprp_load_more_revs admin-ajax.php action

Attack chain
  1. POST /wp-admin/admin-ajax.php action=wprp_load_more_revs with public nonce and notinstring=1) OR (SELECT SLEEP(5))#
Variants tested

Bounded variant search for WP Review Slider Pro SQL injection found no distinct bypass. The parent notinstring payload reproduces before the integer-casting patch and is blocked after it; alternate public fields reaching the same review-query construction were tested and remained fast.

How the agent worked 714 events · 309 tool calls · 42 min
42 minDuration
309Tool calls
170Reasoning steps
714Events
1Dead-ends
Agent activity over 42 min
Support
14
Repro
533
Judge
68
Variant
94
0:0042:00

Root Cause and Exploit Chain for CVE-2026-8441

Versions: Public advisory states versions up to and including 12.7.2. The runtime proof uses a genuine WP Review Slider Pro (Premium) 12.6.7 source zip (sha256: 7f6092f4ea58b5c5c0dba72ba014b9395bf9608f9aeeb95206e80dc14f0b17e5), which contains the vulnerable line-accurate code path.

CVE-2026-8441 is an unauthenticated SQL injection vulnerability in the WP Review Slider Pro WordPress plugin. The vulnerable public AJAX action is wprp_load_more_revs, reached through /wp-admin/admin-ajax.php from a public page rendering the plugin shortcode. The genuine WP Review Slider Pro 12.6.7 code reads the request field notinstring in WP_Review_Pro_Public::wppro_loadmore_revs_ajax(), passes it through sanitize_text_field(), and later concatenates it into an unquoted numeric AND id NOT IN (...) SQL fragment in GetReviews_Functions::wppro_queryreviews(). The reproduction proves the issue against a live WordPress/MariaDB service using the genuine plugin source zip, with time-based and conditional extraction payloads, and then proves a line-accurate fixed patch makes the same endpoint fast.

  • Package/component affected: WP Review Slider Pro (Premium), WordPress plugin slug/codebase wp-review-slider-pro; public AJAX action wprp_load_more_revs; vulnerable helper public/partials/getreviews_class.php.
  • Affected versions: Public advisory states versions up to and including 12.7.2. The runtime proof uses a genuine WP Review Slider Pro (Premium) 12.6.7 source zip (sha256: 7f6092f4ea58b5c5c0dba72ba014b9395bf9608f9aeeb95206e80dc14f0b17e5), which contains the vulnerable line-accurate code path.
  • Risk level and consequences: High. An unauthenticated attacker who can access a public page rendering a WP Review Slider Pro template can send a POST to WordPress admin-ajax.php and inject SQL into the plugin's review query. The reproduced consequence is blind SQL injection sufficient to infer database contents via conditional delays, demonstrated by extracting the first character of the WordPress admin username.

Impact Parity

  • Disclosed/claimed maximum impact: SQL injection with ability to extract database data remotely and unauthenticated.
  • Reproduced impact from this run: Full remote API reachability and blind SQL injection. The script demonstrates normal fast response (~0.106s), repeated SLEEP(5) delays (~5.03s and ~5.02s), SLEEP(3) delay (~3.02s), and a conditional extraction oracle where admin username first-character test for a delays (~3.02s) while the false x test is fast (~0.016s).
  • Parity: full for the SQL injection/data-extraction claim.
  • Not demonstrated: Bulk dumping of the entire database was not performed; the proof stops after a minimal conditional data-extraction primitive to avoid unnecessary exposure. Code execution was not claimed or demonstrated.

Root Cause

The root cause is insufficient SQL neutralization of an attacker-controlled request parameter in a public AJAX handler:

  1. WP_Review_Pro_Public::wppro_loadmore_revs_ajax() is registered for both authenticated and unauthenticated users via wp_ajax_wprp_load_more_revs and wp_ajax_nopriv_wprp_load_more_revs.
  2. The handler performs a nonce check, but the nonce is exposed to public visitors by wp_localize_script() on frontend pages rendering [wprevpro_usetemplate].
  3. The handler reads $_POST['notinstring'] and applies sanitize_text_field(). This WordPress text sanitizer is not an SQL escaping or parameterization mechanism; it does not remove SQL operators such as ) OR (SELECT SLEEP(...))#.
  4. In public/partials/getreviews_class.php, the plugin calls explode(',', $notinstring) and immediately rejoins the array with implode(',', $tempnotinarray), then builds AND id NOT IN ($notinstring) by string concatenation.
  5. The resulting query is executed by $wpdb->get_results() without a prepared statement or integer casting for the NOT IN list.

The line-accurate patch used in the fixed control changes the vulnerable line to cast the CSV list through absint before it is rejoined:

$tempnotinarray = array_filter(array_map('absint', explode(",", $notinstring)));

This preserves numeric review IDs while removing SQL syntax from the NOT IN list. The public advisory names fixed version 12.7.3; no public source commit was available because the plugin is distributed commercially.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh.
  2. The script:
    • verifies the bundled genuine WP Review Slider Pro 12.6.7 zip and records source identity;
    • installs/uses PHP, MariaDB, WordPress, and WP-CLI;
    • activates the genuine plugin in a live WordPress instance;
    • seeds real plugin tables with review/template data and publishes a page containing [wprevpro_usetemplate tid="1"];
    • retrieves the public nonce from that page;
    • sends real HTTP POST requests to /wp-admin/admin-ajax.php with action=wprp_load_more_revs, the nonce, and attacker-controlled notinstring payloads (the request also includes noti for ticket terminology, but the genuine plugin consumes notinstring);
    • captures vulnerable timing and response artifacts;
    • patches the genuine product file in place with a line-accurate integer-casting fix;
    • restarts the PHP service and proves the same payload is fast after patching.
  3. Expected evidence of reproduction:
    • vulnerable SLEEP(5) requests take approximately five seconds twice;
    • vulnerable conditional true extraction takes approximately three seconds while the false condition is fast;
    • fixed SLEEP(5) attempts are fast after the patch;
    • response JSON contains dbcall fields showing injected SQL before the patch and sanitized AND id NOT IN (1) after the patch.

Evidence

  • Primary runtime log: bundle/logs/reproduction_steps.log
  • Evidence summary: bundle/logs/evidence.log
  • Runtime manifest: bundle/repro/runtime_manifest.json
  • Timing summary: bundle/artifacts/timing_summary.json
  • Vulnerable HTTP responses:
    • bundle/artifacts/vuln_sleep5_attempt1_response.json
    • bundle/artifacts/vuln_sleep5_attempt2_response.json
    • bundle/artifacts/vuln_data_true_response.json
    • bundle/artifacts/vuln_data_false_response.json
  • Fixed HTTP responses:
    • bundle/artifacts/fixed_sleep5_warmup_response.json
    • bundle/artifacts/fixed_sleep5_attempt1_response.json
    • bundle/artifacts/fixed_sleep5_attempt2_response.json
  • Source identity and patch evidence:
    • bundle/logs/plugin_source_identity.log
    • bundle/logs/real_notinstring_patch.diff
    • bundle/artifacts/real_vulnerable_getreviews_excerpt.txt
    • bundle/artifacts/real_ajax_handler_excerpt.txt

Key runtime evidence from the final verified run:

Endpoint: POST http://127.0.0.1:36179/wp-admin/admin-ajax.php
Action: wprp_load_more_revs
Nonce source: public page rendering [wprevpro_usetemplate tid="1"]

Vulnerable timings:
  normal notinstring=1,2,3: 0.106269s
  SLEEP(5) attempt 1: 5.028141s
  SLEEP(5) attempt 2: 5.018714s
  SLEEP(3): 3.017385s
  conditional user_login first char == 'a': 3.016486s
  conditional user_login first char == 'x': 0.015544s

Fixed patched-product timings:
  SLEEP(5) warmup after patch (ignored): 0.046941s
  SLEEP(5) attempt 1: 0.016054s
  SLEEP(5) attempt 2: 0.015599s
  normal: 0.016293s

The runtime manifest records entrypoint_kind="api_remote", service_started=true, healthcheck_passed=true, and target_path_reached=true.

Recommendations / Next Steps

  • Update WP Review Slider Pro to version 12.7.3 or later.
  • Apply integer allow-listing/casting to every numeric IN/NOT IN list built from request data; using array_map('absint', ...) is appropriate for review ID lists.
  • Prefer $wpdb->prepare() for all dynamic SQL, and avoid concatenating request-controlled strings into SQL fragments.
  • Add regression tests for wprp_load_more_revs with malicious notinstring values such as 1) OR (SELECT SLEEP(5))#, verifying the resulting query contains only numeric IDs and has no timing delay.
  • Audit related AJAX handlers in the same plugin for similar array/CSV-to-SQL concatenation patterns.

Additional Notes

  • The script was run successfully twice consecutively after fixes, confirming idempotency in a clean runtime directory under bundle/artifacts/runtime.
  • The ticket text abbreviates the affected parameter as noti; the real WP Review Slider Pro code and public advisories identify the consumed parameter as notinstring. The reproduction includes the noti field in requests for traceability, but the genuine plugin's vulnerable sink is $_POST['notinstring'].
  • The fixed control is a line-accurate local patch to the same genuine product file because a public vendor git commit was not available for the commercial plugin.

Variant Analysis & Alternative Triggers for CVE-2026-8441

Versions: versions as tested: Genuine WP Review Slider Pro 12.6.7 source zip (sha256: 7f6092f4ea58b5c5c0dba72ba014b9395bf9608f9aeeb95206e80dc14f0b17e5) and a fixed control consisting of that same source with the line-accurate notinstring integer-casting patch applied. The advisory reports fixed version 12.7.3, but the official commercial 12.7.3 source was not available in this bundle for direct testing.

No distinct bypass or alternate trigger was confirmed for CVE-2026-8441 in this variant stage. The parent issue is an unauthenticated SQL injection in WP Review Slider Pro 12.6.7 where the public AJAX action wprp_load_more_revs passes attacker-controlled notinstring into a numeric AND id NOT IN (...) clause. The variant run revalidated that the original notinstring payload delays before the patch and is fast after the integer-casting patch, then tested materially distinct public fields (textsource, textsearch, textlang, textrtype, and shortcodepageid) that reach the same review-query construction. None produced a timing delay on the fixed control, so this is a negative variant result rather than a confirmed bypass.

Fix Coverage / Assumptions

The original fix relies on the invariant that values entering the numeric id NOT IN (...) list must be review IDs. It changes the vulnerable explode(',', $notinstring) path in public/partials/getreviews_class.php to cast the CSV list through absint() before rejoining it, so SQL metacharacters in notinstring are converted to integers and cannot break out of the NOT IN clause.

The fix explicitly covers:

  • WP_Review_Pro_Public::wppro_loadmore_revs_ajax() reading $_POST['notinstring'] from /wp-admin/admin-ajax.php?action=wprp_load_more_revs.
  • GetReviews_Functions::wppro_queryreviews() building $notinsearchstring = " AND id NOT IN (".$notinstring.") " when $totaltoget > 0.
  • The parent time-based SQL injection payload 1) OR (SELECT SLEEP(3))#, which was reproduced before the patch and blocked after the patch.

The fix does not rewrite every dynamic query fragment in wppro_queryreviews(). The variant analysis therefore reviewed and tested other public filters that are appended to the same SELECT statement, including text search, source/page filtering, language filtering, type filtering, and shortcode page IDs. In the tested runtime, those alternate string candidates did not bypass the fix: their attempted quote breaks were escaped in the final dbcall, and no timing delay occurred.

The target package did not include a SECURITY.md, security policy, or threat-model document in the bundled commercial plugin source. The relevant trust boundary for this assessment is therefore the WordPress public HTTP boundary: unauthenticated visitors can obtain the frontend nonce from a page rendering [wprevpro_usetemplate] and can POST to admin-ajax.php through the plugin's wp_ajax_nopriv_wprp_load_more_revs registration.

Variant / Alternate Trigger

The variant search tested these candidate alternate public fields on the same AJAX endpoint and review-query sink:

  1. textsource: reaches $publicsourcefilter = " AND pageid = '".sanitize_text_field($textsource)."'" in public/partials/getreviews_class.php.
  2. textsearch: reaches $textsearchquery using LIKE filters over reviewer/review/type fields.
  3. textlang: reaches $publiclangfilter = " AND language_code = '".sanitize_text_field($textlang)."'".
  4. textrtype: reaches $publicrtypefilter = "AND type = '".sanitize_text_field($textrtype)."'".
  5. shortcodepageid: reaches $rpagefilter construction through the shortcodepageid argument passed to wppro_queryreviews().

Exact entry point for all attempts:

  • POST /wp-admin/admin-ajax.php
  • action=wprp_load_more_revs
  • Public nonce field: wpfb_nonce, obtained from a frontend page rendering the plugin shortcode.
  • Code path: WP_Review_Pro_Public::wppro_loadmore_revs_ajax() -> GetReviews_Functions::wppro_queryreviews() -> $wpdb->get_results().

All distinct candidate payloads were tested after applying the same notinstring-only fixed control used by the reproduction stage. The fixed-control runtimes were all fast (~0.014-0.017 seconds), so none is claimed as a bypass.

  • Package/component affected: WP Review Slider Pro WordPress plugin, public AJAX action wprp_load_more_revs, review-query helper public/partials/getreviews_class.php.
  • Affected versions as tested: Genuine WP Review Slider Pro 12.6.7 source zip (sha256: 7f6092f4ea58b5c5c0dba72ba014b9395bf9608f9aeeb95206e80dc14f0b17e5) and a fixed control consisting of that same source with the line-accurate notinstring integer-casting patch applied. The advisory reports fixed version 12.7.3, but the official commercial 12.7.3 source was not available in this bundle for direct testing.
  • Risk level and consequences: The parent vulnerability remains high impact on vulnerable versions because unauthenticated attackers can perform blind SQL injection and infer database contents. No additional impact was reproduced for the tested variants after the fixed control.

Impact Parity

  • Disclosed/claimed maximum impact for the parent: Remote unauthenticated SQL injection with database data extraction via the public WordPress AJAX surface.
  • Reproduced impact from this variant run: The script reproduced the parent timing primitive before patching (notinstring SLEEP(3) around 3.11s) and showed it was blocked after the notinstring patch (~0.045s). It then tested five alternate public-field candidates on the fixed control; all were fast and did not execute the timing payload.
  • Parity: none for a new variant/bypass, because no distinct alternate trigger was confirmed. Parent impact parity remains full in the original reproduction, not in this negative variant stage.
  • Not demonstrated: No new data extraction, bulk database dumping, code execution, authentication bypass, or confirmed bypass of the fixed control.

Root Cause

The parent root cause is SQL construction that treated a public request field as a comma-separated numeric ID list without enforcing numeric IDs. Specifically, WP_Review_Pro_Public::wppro_loadmore_revs_ajax() reads $_POST['notinstring'], and GetReviews_Functions::wppro_queryreviews() concatenates it into AND id NOT IN ($notinstring) before executing the query. sanitize_text_field() is not an SQL parameterization mechanism, so payloads such as 1) OR (SELECT SLEEP(3))# break out of the numeric context on vulnerable code.

The fixed control changes that root cause for the parent path by casting each CSV element with absint() before the NOT IN fragment is built. The variant analysis attempted to find the same underlying SQL-neutralization failure from other request fields appended to the same query. Those candidates reached the query-building code, but did not produce SQL execution on the fixed control; response dbcall evidence showed quote characters escaped in string-context filters, and timings stayed below the fast threshold. No public fix commit was available because the plugin is commercially distributed; the tested fixed control is the line-accurate patch recorded in bundle/logs/vuln_variant/variant_notinstring_patch.diff.

Reproduction Steps

  1. Run bundle/vuln_variant/reproduction_steps.sh.
  2. The script:
    • verifies the bundled genuine WP Review Slider Pro 12.6.7 source zip and records source excerpts;
    • installs/uses PHP, MariaDB, WordPress, and WP-CLI;
    • activates the genuine plugin in a live WordPress instance;
    • seeds plugin review/template data and publishes a page containing [wprevpro_usetemplate tid="1"];
    • extracts the public frontend nonce;
    • proves the parent vulnerable notinstring timing payload delays before patching;
    • applies the line-accurate notinstring integer-casting patch;
    • proves the original payload is fast after patching;
    • tests distinct public-field candidates (textsource, textsearch, textlang, textrtype, shortcodepageid) on the fixed control.
  3. Expected evidence:
    • vulnerable original notinstring SLEEP(3) takes >= 2.5 seconds;
    • fixed-control original notinstring SLEEP(3) is fast (< 1.5 seconds);
    • all tested alternate candidate payloads are fast (< 1.5 seconds);
    • the script exits 1 to indicate no variant/bypass was confirmed, but it completes cleanly and is idempotent.

Evidence

Primary evidence locations:

  • bundle/logs/vuln_variant/reproduction_steps.log
  • bundle/logs/vuln_variant/variant_evidence.log
  • bundle/logs/vuln_variant/variant_plugin_source_identity.log
  • bundle/logs/vuln_variant/variant_notinstring_patch.diff
  • bundle/logs/vuln_variant/fixed_version.txt
  • bundle/vuln_variant/artifacts/variant_timing_summary.json
  • bundle/vuln_variant/artifacts/candidate_matrix.json
  • bundle/vuln_variant/runtime_manifest.json

Key second-run timings captured in the evidence log:

  • Vulnerable original notinstring SLEEP(3): 3.109833s
  • Fixed-control original notinstring SLEEP(3): 0.044909s
  • Fixed-control textsource candidate: 0.015890s
  • Fixed-control textsearch candidate: 0.015887s
  • Fixed-control textlang candidate: 0.015000s
  • Fixed-control textrtype candidate: 0.016840s
  • Fixed-control shortcodepageid candidate: 0.014518s

The runtime environment includes PHP 8.5.4, MariaDB 11.8.6, WordPress 6.7.1, and WP Review Slider Pro 12.6.7 from the bundled commercial zip.

Recommendations / Next Steps

  • Keep the notinstring fix as integer casting or an equivalent $wpdb->prepare()/placeholder-based implementation for every ID in the NOT IN list.
  • As defense in depth, refactor GetReviews_Functions::wppro_queryreviews() to build all dynamic filters with $wpdb->prepare() placeholders instead of concatenating sanitized strings into SQL fragments.
  • Treat every public AJAX field as untrusted even when protected by the frontend nonce, because the nonce is intentionally exposed to visitors on pages using the plugin.
  • Add regression tests for the original notinstring payload and for the reviewed alternate fields (textsource, textsearch, textlang, textrtype, and shortcodepageid) to ensure no future change removes escaping or numeric validation.
  • If official 12.7.3 source becomes available, rerun the same variant script against that release and confirm whether the vendor implemented only the notinstring patch or a broader query-builder refactor.

Additional Notes

The reproducer was run twice successfully. Both runs completed cleanly and exited 1 by design because no distinct variant or bypass was found. The official fixed commercial source was unavailable in this bundle, so the fixed target is the line-accurate notinstring patch derived from the reproduction-stage analysis rather than an official 12.7.3 package.

CVE-2026-8441 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:13
0:00
session startedaccounts/fireworks/routers/glm-5p2-fast · CVE-2026-8441 · REPRO-20
0:02
0:04
web search
0:06
web search
0:10
0:11
0:13
web search
0:30
0:30
extract_facts
no facts extracted
0:31
0:31
0:31
supportrepro
0:32
0:32
0:32
0:33
0:33
0:33
0:36
0:38
web search
0:38
0:40
0:52
1:03
1:06
1:07
$echo "=== Check WordPress.org API for wp-review-slider-pro ===" && curl -s "https://api.wordpress.org/plugins/info/1.0/wp-review-slider-pro.json" 2>/dev/null | head -c 2000; echo; echo "=== Check for wp-review-slider (free) ===" && curl -s "https://api.wordpress.org/plugins/info/1.0/wp-review-slider.json" 2>/dev/null | head -c 2000; echo; echo "=== Check for wp-reviews ===" && curl -s "https://api.wordpress.org/plugins/info/1.0/wp-reviews.json" 2>/dev/null | head -c 1000
1.0s
=== Check WordPress.org API for wp-review-slider-pro ===
{"error":"Plugin not found."}
=== Check for wp-review-slider (free) ===
{"error":"Plugin not found."}
=== Check for wp-reviews ===
{"error":"Plugin not found."}
1:08
web search
1:13

Artifacts and Evidence for CVE-2026-8441

Scripts, logs, diffs, and output captured during the reproduction.

08 · How to Fix

How to Fix CVE-2026-8441

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-8441 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-8441

How does the CVE-2026-8441 SQL injection attack work?

An unauthenticated attacker who can access a public page rendering the WP Review Slider Pro shortcode sends a POST to admin-ajax.php with the wprp_load_more_revs action and a crafted notinstring value. Because the value lands in an unquoted numeric IN (...) clause, time-based and conditional payloads let the attacker extract data from the database.

How severe is CVE-2026-8441?

It is rated high severity.

How can I reproduce CVE-2026-8441?

Download the verified script from this page and run it in an isolated environment against a WordPress/MariaDB stack running WP Review Slider Pro (Premium) 12.6.7. It sends time-based and conditional SQL injection payloads via the notinstring field to the wprp_load_more_revs AJAX action and shows data extraction, then confirms a line-accurate fixed patch closes the timing side channel.
11 · References

References for CVE-2026-8441

Authoritative sources for CVE-2026-8441 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.