SECURITY ADVISORY / 01

CVE-2026-5478 Exploit & Vulnerability Analysis

Complete CVE-2026-5478 security advisory with proof of concept (PoC), exploit details, and patch analysis for everest-forms.

everest-forms products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker can read arbitrary files from the server by submitting a form with a file-upload field, injecting path-traversal sequences into the old_files POST parameter, and observing the file contents in the notification email. No prior access or authentication is required; the form merely needs to have a file-upload or image-upload field with entry storage disabled.

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

action=evf_submit_form&form_id=1&everest_forms_1_1=&everest_forms_1_1_old_1=["{\\"value\\":\\"http://target.wordpress.local/wp-content/..\\\\..\\\\..\\\\wp-config.php\\"}"]&everest_forms_1_delete_1=

The attacker's path-traversal payload (..\\..\\..\\wp-config.php) is decoded by the vulnerable regex replacement, which strips everything before wp-content and then concatenates ABSPATH + wp-content/ + the attacker's path. Because no canonicalization occurs, directory boundaries are not enforced. The resolved file path escapes the uploads directory and points to wp-config.php. The plugin attaches this file to the notification email, leaking database credentials and security salts to the attacker's inbox.

Alternatively, if the form processes the request before email delivery, the post-email cleanup routine will call unlink() on the same unvalidated path, deleting the target file and causing denial of service.

What the Patch Did

Before

$uploaded_file = ABSPATH . preg_replace( '/.*wp-content/', 'wp-content', wp_parse_url( $file, PHP_URL_PATH ) );
if ( ! in_array( $uploaded_file, $entry_files ) && file_exists( $uploaded_file ) ) {
    $entry_files [] = $uploaded_file;
}

After

$resolved = $this->resolve_uploads_file_from_url( $file );

if ( false !== $resolved && ! in_array( $resolved, $entry_files, true ) ) {
    $entry_files[] = $resolved;
}

The patch replaced a naive string-concatenation strategy with a dedicated validation function, resolve_uploads_file_from_url(), which performs canonicalization using realpath(), verifies the resolved path stays within the WordPress uploads directory using strpos() boundary checks, and confirms the file exists before returning it. The control is directory confinement — the fix ensures that any attacker-supplied URL, regardless of path-traversal encoding, is resolved to its true filesystem location and then validated against the uploads basedir boundary.

Root Cause

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

The vulnerability flows from two trust boundaries crossed without validation:

  1. Untrusted old_files parameter: The $_POST[ 'everest_forms_' . $form_id . '_old_' . $field_id ] POST parameter accepts JSON-encoded file objects with a value field containing URLs. The plugin assumes these URLs are legitimate server-side upload state, but an attacker can inject arbitrary URLs pointing to any file on the filesystem.

  2. Unsafe path resolution: The code converts the attacker-supplied URL into a filesystem path using only a regex replacement (preg_replace( '/.*wp-content/', 'wp-content', ... )). This regex strips everything up to and including the first occurrence of wp-content, then the string is prepended with ABSPATH. An attacker can encode path-traversal sequences (e.g., ../../../wp-config.php) in the URL; the regex does not canonicalize them, so they remain in the final path and allow directory escape.

The second vulnerability in the patch diff — improper input validation — compounds this by removing type checks on $file_data['value']. The fixed version adds is_string() assertions before attempting path resolution.

Why It Works

The load-bearing line is $resolved = $this->resolve_uploads_file_from_url( $file ), which replaces the entire old path-resolution logic. If you removed it and kept the original regex approach, the bug is still exploitable: an attacker's ../../wp-config.php payload would still reach unlink().

The function itself performs three defenses:

  1. realpath() canonicalization: Resolves all .. and symbolic-link sequences to an absolute path, collapsing the attacker's encoding tricks into a single true path.
  2. Basedir boundary check: Uses strpos() to confirm the canonical path starts with the uploads basedir; if it does not, the function returns false, blocking the attachment and deletion.
  3. File existence check: Only returns the path if the file actually exists, preventing attackers from discovering non-existent files through error messages.

The engineer added the others — is_string() type checks, parameter validation, esc_url_raw() sanitization — to prevent subtle bypasses: an attacker who passes a malformed value field (null, array, object) could cause type confusion or fatal errors that skip the path check. Together, they form a defense-in-depth against both direct traversal and input-smuggling variants.

Hardening Checklist

  • Use wp_normalize_path() and realpath() for all user-controlled file paths: Before any filesystem operation (stat, read, unlink), resolve the path to its canonical form and verify it stays within an expected directory using strpos() prefix matching.
  • Sanitize URL inputs with esc_url_raw() before parsing: Even if you do not execute a URL as a link, parsing untrusted URLs with wp_parse_url() can fail silently or return misleading components; always sanitize first.
  • Validate file locations against a whitelist of allowed directories: Maintain an allow-list of directories (e.g., wp_get_upload_dir()['basedir']) and reject any resolved path that does not fall within one of them.
  • Add type assertions (is_string(), is_array()) on all unserialized and POST-sourced data: JSON decoding can return unexpected types; check the type before accessing fields or passing to functions expecting a specific type.
  • Prefer a dedicated upload/file-retrieval API over manual path construction: If your plugin re-implements file handling, audit it against wp_safe_remote_get() and wp_get_upload_dir() behavior to catch trust-boundary violations.

References

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

Frequently asked questions about CVE-2026-5478

What is CVE-2026-5478?

CVE-2026-5478 is a security vulnerability identified in everest-forms. 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-5478?

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

How does CVE-2026-5478 get exploited?

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

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

CVE-2026-5478 affects everest-forms. 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-5478?

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

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

The severity rating and CVSS scoring for CVE-2026-5478 affecting everest-forms is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.