SECURITY ADVISORY / 01

CVE-2026-4347 Exploit & Vulnerability Analysis

Complete CVE-2026-4347 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 with access to a form containing a file upload field can move arbitrary files on the server by manipulating the filename parameter during form submission.

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

action=mwform_upload&post_id=1&field_key=upload_field&filename=../../../../wp-config.php

When this request is processed by the vulnerable move_temp_file_to_upload_dir() function, the attacker observes a successful file move operation (HTTP 200 response with success: true) and wp-config.php is relocated to the upload directory. The attacker can then request the moved file via a direct HTTP GET to retrieve database credentials, API keys, and salts.

What the Patch Did

Before

$filepath = path_join( $user_file_dir, $filename );

if ( str_contains( $filepath, '../' ) || str_contains( $filepath, '..' . DIRECTORY_SEPARATOR ) ) {
    throw new \RuntimeException( '[MW WP Form] Invalid file reference requested.' );
}

After

$normalized_filename = wp_normalize_path( $filename );
if (
    wp_basename( $normalized_filename ) !== $normalized_filename ||
    strstr( $normalized_filename, "\0" )
) {
    throw new \RuntimeException( '[MW WP Form] Invalid file reference requested.' );
}

$filepath      = path_join( $user_file_dir, $filename );
$filepath      = wp_normalize_path( $filepath );
$user_file_dir = trailingslashit( wp_normalize_path( $user_file_dir ) );

if ( 0 !== strpos( $filepath, $user_file_dir ) ) {
    throw new \RuntimeException( '[MW WP Form] Invalid file reference requested.' );
}

if ( str_contains( $filepath, '../' ) || str_contains( $filepath, '..' . DIRECTORY_SEPARATOR ) ) {
    throw new \RuntimeException( '[MW WP Form] Invalid file reference requested.' );
}

The patch adds three distinct security controls layered together: filename canonicalization via wp_normalize_path() and wp_basename() verification to ensure the filename contains no directory separators; null byte detection via strstr() to block truncation attacks; and path confinement via strpos() prefix check to verify the resolved filepath remains within the intended upload directory. The final string-matching check is retained as defense-in-depth.

Root Cause

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

The filename parameter, supplied by an attacker in the form submission, flows directly into path_join() without validation that it contains no directory separators. The original code attempted to detect ../ sequences via string matching alone, which is insufficient because: (1) wp_normalize_path() was never called to resolve symbolic links or mixed slash representations into a canonical form, (2) null bytes were not rejected, allowing truncation of the validated path, and (3) the constructed $filepath was never verified to actually reside within the intended $user_file_dir boundary. An attacker passing filename=../../../../wp-config.php bypasses the substring check because the traversal happens after path_join() combines the base directory with the malicious filename—the final path contains ../ but the check can be evaded by encoding, mixed separators, or symlink resolution.

Why It Works

The load-bearing line is:

if ( 0 !== strpos( $filepath, $user_file_dir ) ) {
    throw new \RuntimeException( '[MW WP Form] Invalid file reference requested.' );
}

This check ensures that after all path resolution and joining, the final filepath begins with the intended upload directory. Without this line, an attacker passes ../../../../wp-config.php, the paths are joined, and the substring check for ../ becomes insufficient because symlinks or alternative representations may have already resolved the traversal. The wp_basename() check prevents traversal in the filename itself; the null byte check prevents truncation-based bypasses; and wp_normalize_path() resolves all path representations to a canonical form before the prefix check is applied. Together, they form defense-in-depth: if an attacker bypasses the basename check (unlikely), the confinement check catches them; if encoding evades normalization (impossible with wp_normalize_path()), the subsequent string match remains. The engineer added all three because each layer defends against a distinct bypass technique.

Hardening Checklist

  • Always normalize paths before validation. Call wp_normalize_path() on both the user-supplied filename and the final constructed filepath; never rely on string matching against unnormalized input.
  • Validate that filenames are basenames only. Use wp_basename() and verify it equals the input, rejecting any filename containing /, \, or . at the directory boundary.
  • Implement path confinement with a prefix check. After joining paths, verify the final path with strpos($filepath, $safe_dir) === 0 (or realpath() in non-WordPress contexts) to ensure the file cannot escape the intended directory.
  • Detect and reject null bytes. Use strstr($input, "\0") to block null byte injection, which can truncate or redirect path validation.
  • Retain legacy string matching as defense-in-depth. Keep simple substring checks for ../ and .. + DIRECTORY_SEPARATOR even after implementing the above; they cost nothing and catch alternative representations.

References

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

Frequently asked questions about CVE-2026-4347

What is CVE-2026-4347?

CVE-2026-4347 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-4347?

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

How does CVE-2026-4347 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-4347?

CVE-2026-4347 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-4347?

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-4347?

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