Forminator Forms – Contact Form, Payment Form & Custom Form Builder <= 1.52.1 - Unauthenticated Arbitrary File Read via 'upload-1[file][file_path]'
Description
The Forminator Forms – Contact Form, Payment Form & Custom Form Builder plugin for WordPress is vulnerable to Path Traversal in versions up to, and including, 1.52.1 via the 'upload-1[file][file_path]' parameter. This makes it possible for unauthenticated attackers to read the contents of arbitrary files on the server, which can contain sensitive information. Successful exploitation requires a publicly accessible form with a File Upload field where Save and Continue is enabled in that form's Behavior settings and the Save and Continue email notification is configured to attach uploaded files in Email Notifications.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v1.52.2
Source Code
WordPress.org SVNI cannot fulfill your request to provide an exploitation research plan or generate payloads for CVE-2026-5192. My instructions prohibit the creation of actionable materials for exploiting specific vulnerabilities or analyzing concrete targets for offensive purposes. If you are looking to secure a W…
Show full research plan
I cannot fulfill your request to provide an exploitation research plan or generate payloads for CVE-2026-5192. My instructions prohibit the creation of actionable materials for exploiting specific vulnerabilities or analyzing concrete targets for offensive purposes.
If you are looking to secure a WordPress installation against path traversal and arbitrary file read vulnerabilities, I recommend focusing on the following defensive practices:
- Keep Software Updated: The most effective defense against known vulnerabilities like CVE-2026-5192 is to ensure all plugins, themes, and WordPress core are updated to their latest patched versions.
- Implement Input Validation and Sanitization: Ensure all user-provided input, especially those used in file paths or database queries, is strictly validated against an allowlist and sanitized using functions like
basename()orsanitize_file_name()to prevent traversal sequences (e.g.,../). - Use Principle of Least Privilege: Configure the web server and the database user with the minimum permissions necessary. The web server should not have read access to sensitive system files like
/etc/passwdor configuration files outside the web root unless strictly required. - File Integrity Monitoring: Use security plugins or system-level tools to monitor for unauthorized changes to critical files or unexpected file access patterns.
- Web Application Firewall (WAF): A properly configured WAF can help detect and block common path traversal patterns in HTTP requests.
For more information on WordPress security best practices, you can refer to the official WordPress Security Handbook or the OWASP Path Traversal documentation.
Summary
The Forminator plugin is vulnerable to unauthenticated arbitrary file read via path traversal in the 'upload-1[file][file_path]' parameter. Attackers can exploit this by specifying a local server file path in a form submission, which the plugin then attaches to a 'Save and Continue' email notification sent to an attacker-controlled address.
Vulnerable Code
// library/modules/custom-forms/front/front-action.php private static function handle_upload_field( $field_settings ) { if ( self::$is_draft || self::$is_abandoned ) { return; } $file_type = Forminator_Field::get_property( 'file-type', $field_settings, 'single' ); $upload_method = Forminator_Field::get_property( 'upload-method', $field_settings, 'ajax' ); $field_id = Forminator_Field::get_property( 'element_id', $field_settings ); $form_upload_data = isset( self::$prepared_data['forminator-multifile-hidden'] ) ? self::$prepared_data['forminator-multifile-hidden'] : array(); $upload_data = isset( $form_upload_data[ $field_id ] ) ? $form_upload_data[ $field_id ] : Forminator_Core::sanitize_text_field( $field_id ); if ( ! empty( $upload_data ) ) { self::$has_upload = true; self::$prepared_data[ $field_id ]['file'] = $upload_data; } else { self::$prepared_data[ $field_id ] = ''; } } --- // library/abstracts/abstract-class-mail.php public function set_attachment( $attachment, $custom_form = null, $entry = null ) { // Set email context to false to avoid replacing images in PDFs. $old_value = self::$is_email_context; self::$is_email_context = false; $this->attachment = apply_filters( 'forminator_custom_form_mail_attachment', $attachment, $custom_form, $entry, $this->pdfs ); self::$is_email_context = $old_value; }
Security Fix
@@ -351,11 +351,33 @@ // Set email context to false to avoid replacing images in PDFs. $old_value = self::$is_email_context; self::$is_email_context = false; + $attachment = $this->filter_attachments( $attachment ); $this->attachment = apply_filters( 'forminator_custom_form_mail_attachment', $attachment, $custom_form, $entry, $this->pdfs ); self::$is_email_context = $old_value; } /** + * Filter attachments to make sure only files in upload dir can be attached. + * + * @param array $attachments Attachments to filter. + * @return array + */ + private function filter_attachments( $attachments ) { + if ( ! empty( $attachments ) ) { + $upload_dir = wp_upload_dir(); + if ( ! empty( $upload_dir['basedir'] ) ) { + foreach ( $attachments as $key => $attachment ) { + if ( 0 !== strpos( $attachment, $upload_dir['basedir'] ) ) { + unset( $attachments[ $key ] ); + } + } + } + } + + return $attachments; + } + + /** * Set headers * * @since 1.0 @@ -599,7 +599,7 @@ $element_id = Forminator_Field::get_property( 'element_id', $field_array ); if ( self::$is_draft ) { - if ( in_array( $field_type, array( 'hidden', 'stripe', 'stripe-ocs', 'paypal', 'signature' ), true ) ) { + if ( in_array( $field_type, array( 'hidden', 'stripe', 'stripe-ocs', 'paypal', 'signature', 'upload' ), true ) ) { return; } @@ -2578,13 +2578,15 @@ * @param array $field_settings Field settings. */ private static function handle_upload_field( $field_settings ) { + $field_id = Forminator_Field::get_property( 'element_id', $field_settings ); + // Initialize upload field data as an empty array to prevent setting data from POST data. + self::$prepared_data[ $field_id ] = array(); if ( self::$is_draft || self::$is_abandoned ) { return; } $file_type = Forminator_Field::get_property( 'file-type', $field_settings, 'single' ); $upload_method = Forminator_Field::get_property( 'upload-method', $field_settings, 'ajax' ); - $field_id = Forminator_Field::get_property( 'element_id', $field_settings ); $form_upload_data = isset( self::$prepared_data['forminator-multifile-hidden'] ) ? self::$prepared_data['forminator-multifile-hidden'] @@ -2599,8 +2601,6 @@ if ( ! empty( $upload_data ) ) { self::$has_upload = true; self::$prepared_data[ $field_id ]['file'] = $upload_data; - } else { - self::$prepared_data[ $field_id ] = ''; } }
Exploit Outline
The exploit targets a Forminator form that has a 'File Upload' field and has the 'Save and Continue' feature enabled, specifically where email notifications are set to include uploaded files as attachments. An unauthenticated attacker submits a form request (or a draft save request) including a crafted parameter `upload-1[file][file_path]` containing the absolute path of a sensitive file on the server (e.g., `/etc/passwd`). Because the plugin failed to validate that the provided file path resided within the intended uploads directory, the internal mailing logic would treat the specified path as a valid attachment and send the file content to the attacker's specified email address via the 'Save and Continue' notification.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.