Skip to main content
Vulnerability Database/CVE-2026-109221

CVE-2026-109221: Groundhogg WordPress Path Traversal Flaw

CVE-2026-109221 is a path traversal flaw in Groundhogg WordPress plugin that allows authenticated attackers to delete critical files, potentially leading to remote code execution. This article covers technical details, affected versions, impact analysis, and mitigation strategies.

Published:

CVE-2026-109221 Overview

CVE-2026-109221 is an arbitrary file deletion vulnerability in the Groundhogg CRM, Newsletters, and Marketing Automation plugin for WordPress. The flaw affects all versions up to and including 4.9.3 and stems from insufficient file path validation in the copy_file function. Authenticated attackers holding the plugin-defined import_contacts capability can delete arbitrary files on the server. Deleting critical files such as wp-config.php can enable remote code execution by forcing WordPress into a reinstallation state. The import_contacts capability is granted by default to the plugin's custom Sales Representative role, lowering the privilege barrier for exploitation.

Critical Impact

Authenticated users with Sales Representative-level access can delete arbitrary files on the server, including wp-config.php, which can be leveraged to achieve remote code execution.

Affected Products

  • Groundhogg CRM, Newsletters, and Marketing Automation plugin for WordPress
  • All versions up to and including 4.9.3
  • WordPress sites assigning the Sales Representative role or granting the import_contacts capability

Discovery Timeline

  • 2026-10-16 - CVE-2026-109221 published to NVD
  • 2026-10-16 - Last updated in NVD database

Technical Details for CVE-2026-109221

Vulnerability Analysis

The vulnerability is a path traversal weakness classified as [CWE-22]. It resides in the copy_file function within includes/classes/traits/file-box.php. The function accepts a $url_or_path parameter and, when the path resolves to a local file, assigns it directly as the tmp_name for subsequent file handling. Downstream WordPress sideloading routines then move or delete the referenced file. Because the function did not restrict the source path to the uploads directory, an attacker could point copy_file at any file readable by the web server process, including configuration files and plugin code.

Root Cause

The root cause is missing validation that the supplied path resides within the WordPress uploads directory. Prior to the fix, tmp_name was set to the attacker-controlled $url_or_path whenever file_exists() returned true. The sideload process then operated on the original file, deleting it when the import rejected the entry. This allowed an authenticated attacker to coerce the plugin into deleting arbitrary files on disk.

Attack Vector

Exploitation requires an authenticated session with the import_contacts capability, which the plugin grants by default to Sales Representatives. The attacker triggers the import contacts workflow, the tools page file handling, the REST API, or webhook ingestion with a crafted file path parameter. The copy_file function then processes the path and the downstream pipeline deletes the target file. Deleting wp-config.php returns WordPress to its installation wizard, allowing an attacker to reconnect the site to an attacker-controlled database and achieve remote code execution.

php
// Security patch in includes/classes/traits/file-box.php
// Source: https://github.com/groundhoggwp/groundhogg/commit/e319e4a849bfbb07cccfbac8558ad6bf07a7fdc0

			return new WP_Error( 'not_copyable', 'This file can\'t be uploaded.' );
		}

+		if ( file_exists( $url_or_path ) ) {
+
+			// A local file is only copied from inside the uploads directory
+			if ( ! files()::is_file_within_directory( $url_or_path, wp_get_upload_dir()['basedir'] ) ) {
+				return new WP_Error( 'nope', 'File upload not allowed.' );
+			}
+
+			// The original is never the file that gets sideloaded, that is moved into place, or deleted if it's rejected
+			$tmp_name = wp_tempnam( wp_basename( $url_or_path ) );
+
+			if ( ! $tmp_name || ! copy( $url_or_path, $tmp_name ) ) {
+				return new WP_Error( 'copy_failed', 'The file could not be copied.' );
+			}
+		} else {
+			$tmp_name = download_url( $url_or_path );
+
+			if ( is_wp_error( $tmp_name ) ) {
+				return $tmp_name;
+			}
+		}
+
		$file = [
			'name'     => wp_basename( $url_or_path ),
			// Original filename on the user's system
-			'tmp_name' => file_exists( $url_or_path ) ? $url_or_path : download_url( $url_or_path ),
+			'tmp_name' => $tmp_name,

The patch validates that any local path passed to copy_file resides within the uploads directory and copies the file to a temporary name before further processing.

Detection Methods for CVE-2026-109221

Indicators of Compromise

  • Missing or recently modified wp-config.php, wp-settings.php, or active theme and plugin files on hosts running Groundhogg at or below 4.9.3.
  • WordPress installation wizard presented at site root without administrator action.
  • Unexpected contact import jobs, REST API calls, or webhook deliveries referencing absolute file paths such as /var/www/html/wp-config.php.
  • Audit log entries showing Sales Representative accounts initiating imports immediately before file deletions.

Detection Strategies

  • Monitor file integrity on WordPress document roots for deletions of configuration, plugin, and theme PHP files.
  • Inspect Groundhogg import logs for file path values that resolve outside the WordPress uploads directory.
  • Alert on web requests to Groundhogg import, tools, REST, or webhook endpoints submitted by non-administrative roles.

Monitoring Recommendations

  • Enable WordPress and web server access logging and ship events to a centralized log platform for correlation.
  • Track role assignments and capability grants for the plugin-defined Sales Representative role.
  • Baseline normal Groundhogg background job activity and alert on anomalies in import-contacts.php execution patterns.

How to Mitigate CVE-2026-109221

Immediate Actions Required

  • Upgrade the Groundhogg plugin to version 4.9.4 or later on every WordPress site in the environment.
  • Audit all user accounts assigned the Sales Representative role or granted the import_contacts capability and remove unnecessary privileges.
  • Review file integrity on affected hosts and restore any deleted configuration files from known-good backups.

Patch Information

The vendor released version 4.9.4 on 2026-10-13 with hardened file handling in copy_file. The fix restricts local file sources to the WordPress uploads directory and copies files to a temporary name before sideloading. See the GitHub commit e319e4a849 and the Wordfence advisory FB5100 for full technical details.

Workarounds

  • Revoke the import_contacts capability from the Sales Representative role until the plugin is upgraded.
  • Disable the Groundhogg plugin on sites where immediate patching is not possible.
  • Restrict access to the WordPress REST API and webhook endpoints to trusted networks and administrative accounts.
bash
# Example: remove the import_contacts capability from the Sales Representative role using WP-CLI
wp role list
wp cap remove sales_representative import_contacts
wp plugin update groundhogg --version=4.9.4

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.