Collapsing Archives <= 3.0.7 - Authenticated (Contributor+) SQL Injection
Description
The Collapsing Archives plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 3.0.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with contributor-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=3.0.7What Changed in the Fix
Changes introduced in v3.0.8
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-32365 ## 1. Vulnerability Summary The **Collapsing Archives** plugin (versions <= 3.0.7) is vulnerable to an authenticated SQL injection (Contributor+ level) due to improper sanitization and preparation of user-supplied parameters within its Gutenberg block a…
Show full research plan
Exploitation Research Plan - CVE-2026-32365
1. Vulnerability Summary
The Collapsing Archives plugin (versions <= 3.0.7) is vulnerable to an authenticated SQL injection (Contributor+ level) due to improper sanitization and preparation of user-supplied parameters within its Gutenberg block attributes. Specifically, the parameters inExcludeYears, sort, and post_type are concatenated directly into SQL queries within the list_archives() function in collapsArchList.php.
2. Attack Vector Analysis
- Vulnerable Hook: Gutenberg block rendering (Gutenberg blocks pass attributes to a server-side
render_callback). - Endpoint: Any page or post where a Contributor (or higher) can insert a block, or the REST API
block-rendererendpoint. - Vulnerable Parameters:
inExcludeYears,sort,post_type. - Authentication: Authenticated (Contributor+). Contributors can create posts and define block attributes.
- Preconditions: The plugin must be active, and the attacker must have a user account with
contributor,author,editor, oradministratorroles.
3. Code Flow
- Entry Point: A Contributor creates or edits a post containing the
create-block/collapsing-archivesblock (registered incollapsArch.phpviacreate_block_collapsArch_block_init). - **Registration
Summary
The Collapsing Archives plugin for WordPress is vulnerable to SQL Injection due to the direct concatenation of block attributes like 'inExcludeYears' into SQL queries without proper sanitization or use of prepared statements. This allows authenticated users with Contributor-level permissions or higher to execute arbitrary SQL commands and extract sensitive information from the database.
Vulnerable Code
// collapsArchList.php lines 64-80 if ( !empty($inExcludeYear) && !empty($inExcludeYears) ) { $exterms = preg_split('/[,]+/',$inExcludeYears); if ($inExcludeYear=='include') { $in='IN'; } else { $in='NOT IN'; } if ( count($exterms) ) { foreach ( $exterms as $exterm ) { if (empty($inExclusionsYear)) $inExclusionsYear = "'" .$exterm . "'"; else $inExclusionsYear .= ", '" . $exterm . "' "; } } } if ( empty($inExclusionsYear) ) { $inExcludeYearQuery = ""; } else { $inExcludeYearQuery ="AND YEAR($wpdb->posts.post_date) $in ($inExclusionsYear)"; } --- // collapsArchList.php lines 91-106 $postquery= "SELECT $wpdb->terms.slug, $wpdb->posts.ID, $wpdb->posts.post_name, $wpdb->posts.post_title, $wpdb->posts.post_author, $wpdb->posts.post_date, YEAR($wpdb->posts.post_date) AS 'year', MONTH($wpdb->posts.post_date) AS 'month' , $wpdb->posts.post_type FROM $wpdb->posts LEFT JOIN $wpdb->term_relationships ON $wpdb->posts.ID = $wpdb->term_relationships.object_id LEFT JOIN $wpdb->term_taxonomy ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id LEFT JOIN $wpdb->terms ON $wpdb->terms.term_id = $wpdb->term_taxonomy.term_id WHERE post_status='publish' $postTypeQuery $inExcludeYearQuery $inExcludeCatQuery GROUP BY $wpdb->posts.ID ORDER BY $wpdb->posts.post_date $sort"; $allPosts=$wpdb->get_results($postquery);
Security Fix
@@ -52,28 +52,28 @@ } else { $inExcludeCatQuery ="AND $wpdb->terms.slug $in ($inExclusionsCat)"; } - $inExclusionsYear = array(); + $inExcludeYearQuery = ""; if ( !empty($inExcludeYear) && !empty($inExcludeYears) ) { - $exterms = preg_split('/[,]+/',$inExcludeYears); - if ($inExcludeYear=='include') { - $in='IN'; - } else { - $in='NOT IN'; - } + $exterms = preg_split('/[,]+/', $inExcludeYears); + // Validate $inExcludeYear to prevent SQL injection. + $in = ( $inExcludeYear === 'include' ) ? 'IN' : 'NOT IN'; if ( count($exterms) ) { + $sanitized_years = array(); foreach ( $exterms as $exterm ) { - if (empty($inExclusionsYear)) - $inExclusionsYear = "'" .$exterm . "'"; - else - $inExclusionsYear .= ", '" . $exterm . "' "; + $year = absint( trim( $exterm ) ); + if ( $year > 0 ) { + $sanitized_years[] = $year; + } + } + if ( ! empty( $sanitized_years ) ) { + $placeholders = implode( ', ', array_fill( 0, count( $sanitized_years ), '%d' ) ); + $inExcludeYearQuery = $wpdb->prepare( + "AND YEAR($wpdb->posts.post_date) $in ($placeholders)", + $sanitized_years + ); } } } - if ( empty($inExclusionsYear) ) { - $inExcludeYearQuery = ""; - } else { - $inExcludeYearQuery ="AND YEAR($wpdb->posts.post_date) $in ($inExclusionsYear)"; - }
Exploit Outline
To exploit this vulnerability, an attacker must have at least Contributor-level authentication. The attacker can then utilize the WordPress REST API block-renderer endpoint (`/wp-json/wp/v2/block-renderer/create-block/collapsing-archives`) or create a post containing the plugin's Gutenberg block. By manipulating the `attributes` object in the request, specifically the `inExcludeYears` parameter, the attacker can inject SQL syntax. For example, a payload such as `2024') OR (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -` will break out of the string encapsulation in the `list_archives()` function, allowing the attacker to perform time-based blind SQL injection or extract data using UNION-based techniques.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.