SECURITY ADVISORY / 01

CVE-2026-5436 Exploit & Vulnerability Analysis

Complete CVE-2026-5436 security advisory with proof of concept (PoC), exploit details, and patch analysis for mw-wp-form.

mw-wp-form products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker can move arbitrary files on the server if the form contains a file upload field and "Saving inquiry data in database" is enabled.

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded

action=mwf_form_submit&form_key=<valid_form_key>&mwf_upload_files[../../wp-config.php]=wp-config.php

The server accepts the request and moves wp-config.php into the uploads directory. If the attacker replaces wp-config.php with a malicious version before the move occurs, or if the file's new location is web-accessible, code execution follows. The response contains no obvious error — the form processes normally while the file operation executes in the background during regenerate_upload_file_keys() iteration.


What the Patch Did

Before

$form_id  = MWF_Functions::get_form_id_from_form_key( $this->Data->get_form_key() );
$filepath = MW_WP_Form_Directory::generate_user_filepath( $form_id, $key, $upload_filename );
if ( ! file_exists( $filepath ) ) {
    continue;
}

After

$form_id = MWF_Functions::get_form_id_from_form_key( $this->Data->get_form_key() );

try {
    $filepath = MW_WP_Form_Directory::generate_user_filepath( $form_id, $key, $upload_filename );
} catch ( \Exception $e ) {
    error_log( $e->getMessage() );
    continue;
}

if ( ! $filepath || ! file_exists( $filepath ) ) {
    continue;
}

The patch added exception handling and explicit null-checking of the $filepath output before use. However, the real load-bearing fix lives in class.directory.php: two new validation methods, _is_valid_path_segment() and _is_within_expected_dir_candidate(), now reject path traversal sequences (.., .), absolute paths, and any filepath that escapes the intended user directory tree. The $key parameter is now validated by _is_valid_path_segment() before path_join() receives it, preventing the root cause: the WordPress path_join() function returns absolute paths unchanged, and the old code trusted that the supplied $key was safe to join.


Root Cause

CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The attacker-controlled mwf_upload_files[] POST parameter array keys flow into the plugin's Data model via _set_request_valiables(), where they are stored as field keys without validation. During form processing, regenerate_upload_file_keys() iterates over these keys and passes them as the $name argument to generate_user_filepath(). The vulnerable code in class.directory.php checks only that wp_basename($filename) === $filename — ensuring the filename itself contains no slashes — but does not validate the $name parameter. When $name is set to ../../wp-config.php, the function calls path_join($user_file_dir, '../../wp-config.php'). Because path_join() returns absolute paths unchanged and ../../wp-config.php resolves to an absolute path, the function returns the absolute path to wp-config.php rather than a path confined to the upload directory. The file_exists() check then passes because wp-config.php genuinely exists at the root level, and move_temp_file_to_upload_dir() proceeds to rename() the file into the uploads folder.


Why It Works

The load-bearing fix is the new _is_valid_path_segment() method, which rejects inputs where path_is_absolute() returns true or where the value equals . or ... Remove this check, and an attacker can still craft relative traversal sequences such as ../../../wp-config.php, or supply an absolute path like /var/www/wp-config.php, both of which path_join() will honor. The _is_within_expected_dir_candidate() method serves as defence-in-depth: even if a creative input bypasses the first check, the second method canonicalizes both the resolved filepath and the expected user directory, then confirms via strpos() that the filepath is either equal to or a child of the expected directory. The try-catch block and null-check in class.main.php are hygiene: they prevent a crash if path generation fails, but without the two new validation methods in class.directory.php, attackers would still succeed because generate_user_filepath() would not throw an exception — it would return the attacker's target path unmolested.


Hardening Checklist

  • Whitelist path segment components: Use _is_valid_path_segment() logic (or equivalent) to reject path traversal sequences (., ..), null bytes, absolute paths, and directory separators before passing user input to path_join() or any filesystem operation. WordPress provides path_is_absolute() and wp_basename() as primitives.

  • Post-resolution confinement check: After calling path_join() and normalizing with wp_normalize_path(), always verify the final resolved path lies within the intended parent directory using strpos() or equivalent prefix matching on the canonical (realpath'd) directory boundary.

  • Reject empty / invalid path segments: Check that path inputs are non-empty strings and normalize them before validation. Use wp_normalize_path() on user input before testing against path-safety rules.

  • Wrap path generation in exception handling: Call filesystem operations inside try-catch blocks and log exceptions without exposing details in user-facing responses. This prevents both crashes and information leakage if path validation fails.

  • Test path traversal inputs in your test suite: Add unit tests covering ., .., absolute paths, and null bytes as inputs to any function that constructs file paths from user data. Run these tests on every form field that touches the filesystem.


References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-5436

Frequently asked questions about CVE-2026-5436

What is CVE-2026-5436?

CVE-2026-5436 is a security vulnerability identified in mw-wp-form. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-5436?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-5436. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-5436 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting mw-wp-form. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-5436?

CVE-2026-5436 affects mw-wp-form. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-5436?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for mw-wp-form.

What is the CVSS score for CVE-2026-5436?

The severity rating and CVSS scoring for CVE-2026-5436 affecting mw-wp-form is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.