CVE-2026-6964

Video Conferencing with Zoom <= 4.6.7 - Missing Authorization to Unauthenticated Zoom SDK Credential Exposure via 'get_auth' AJAX Action

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.6.8
Patched in
1d
Time to patch

Description

The Video Conferencing with Zoom plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 4.6.7. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to obtain the site's Zoom SDK API key and a freshly-signed JWT that can be used with the Zoom Web SDK to join any Zoom meeting associated with those credentials without a legitimate invitation.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=4.6.7
PublishedJune 15, 2026
Last updatedJune 16, 2026

What Changed in the Fix

Changes introduced in v4.6.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the technical steps required to analyze and demonstrate the missing authorization vulnerability in the "Video Conferencing with Zoom" plugin (CVE-2026-6964). ### 1. Vulnerability Summary The vulnerability is a **Missing Authorization** flaw located in the `get_auth` AJAX…

Show full research plan

This research plan outlines the technical steps required to analyze and demonstrate the missing authorization vulnerability in the "Video Conferencing with Zoom" plugin (CVE-2026-6964).

1. Vulnerability Summary

The vulnerability is a Missing Authorization flaw located in the get_auth AJAX action. The plugin registers this action for unauthenticated users (wp_ajax_nopriv_get_auth) but fails to implement any capability checks (e.g., current_user_can) within the handler. While the endpoint is protected by a WordPress nonce, the nonce is exposed to unauthenticated visitors on any page where the Zoom Web SDK is initialized. Consequently, an attacker can retrieve the nonce, call the AJAX action, and obtain the site's Zoom SDK Key and a signed JWT (signature) to join meetings.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: get_auth
  • Parameters:
    • action: get_auth (Required)
    • noncce: A valid WordPress nonce for the action _nonce_zvc_security (Required)
    • meeting_id: A Zoom meeting ID (Required to generate the JWT)
  • Authentication: None (Unauthenticated)
  • Preconditions: The "Join via Browser" (SDK) feature must be enabled in the plugin settings.

3. Code Flow

  1. Entry Point: The AJAX request is received by WordPress and dispatched to the handler registered in includes/admin/class-zvc-admin-ajax.php:
    add_action('wp_ajax_nopriv_get_auth', array($this, 'get_auth'));
    
  2. Nonce Verification: The get_auth() function calls check_ajax_referer:
    public function get_auth() {
        check_ajax_referer('_nonce_zvc_security', 'noncce');
        // ...
    
  3. Credential Retrieval: If the nonce is valid and SDK is enabled via vczapi_is_sdk_enabled(), the plugin fetches sensitive credentials:
    $sdk_key    = get_option('vczapi_sdk_key');
    $secret_key = get_option('vczapi_sdk_secret_key');
    
  4. JWT Generation: The plugin generates a signature using the secret key via generate_sdk_signature():
    $signature  = $this->generate_sdk_signature($sdk_key, $secret_key, $meeting_id, 0);
    
  5. Data Exposure: The SDK Key and Signature are returned in a JSON response:
    wp_send_json_success(['sig' => $signature, 'key' => $sdk_key, 'type' => 'sdk']);
    

4. Nonce Acquisition Strategy

The nonce is required to pass the check_ajax_referer check. The plugin exposes this nonce via wp_localize_script to support the frontend "Join via Browser" functionality.

  • Trigger: The scripts are enqueued when a Zoom Meeting post is viewed or when the [zoom_join_via_browser] shortcode is present.
  • Acquisition Steps:
    1. Create a Zoom Meeting post or a page with the [zoom_join_via_browser] shortcode.
    2. Navigate to the page as an unauthenticated user.
    3. Extract the nonce from the global JavaScript object zvc_ajx.
  • JS Extraction: Use browser_eval to get the value of window.zvc_ajx?.zvc_security.

5. Exploitation Strategy

This strategy assumes an isolated environment with the plugin installed and configured.

  1. Extract Nonce:
    • Navigate to a page containing a Zoom meeting (e.g., the meeting post created in Step 6).
    • Execute browser_eval("window.zvc_ajx.zvc_security") to obtain the nonce.
  2. Trigger Credential Exposure:
    • Use the http_request tool to send a POST request to the AJAX endpoint.
    • URL: http://<target>/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=get_auth&noncce=<NONCE>&meeting_id=123456789
  3. Capture Response: The response should be a JSON object containing the key and sig.

6. Test Data Setup

To facilitate the PoC, the environment must be configured as follows:

  • Configure Zoom API: Use WP-CLI to set dummy Zoom credentials (required for the logic to reach the sink):
    wp option update zoom_api_key "dummy_api_key"
    wp option update zoom_api_secret "dummy_api_secret"
    wp option update vczapi_sdk_key "test_sdk_key"
    wp option update vczapi_sdk_secret_key "test_sdk_secret_01234567890123456789"
    
  • Enable SDK:
    wp option update vczapi_set_sdk_feature_parent 1
    
  • Create Meeting: Create a Zoom Meeting post to ensure the frontend scripts (and nonce) load:
    wp post create --post_type=zoom-meetings --post_title="Exploit Test Meeting" --post_status=publish
    

7. Expected Results

A successful exploit will return an HTTP 200 response with a JSON body similar to:

{
    "success": true,
    "data": {
        "sig": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "key": "test_sdk_key",
        "type": "sdk"
    }
}

The sig value is a valid JWT signed with the vczapi_sdk_secret_key.

8. Verification Steps

After performing the HTTP request, verify the leaked data matches the database:

  1. Compare the key in the JSON response with the output of wp option get vczapi_sdk_key.
  2. Decode the sig (JWT) using a tool or script to verify the sdkKey claim matches the vczapi_sdk_key and the mn (meeting number) claim matches the meeting_id sent in the request.

9. Alternative Approaches

If the zvc_ajx object is not found on the page:

  • Search the HTML source for zvc_ajx to see if it is localized under a different variable name or embedded in a script block.
  • Check if the shortcode [zoom_api_link meeting_id="12345"] or the Gutenberg block for Zoom Meetings enqueues the necessary assets.
  • If vczapi_is_sdk_enabled() returns false, the exploit will return an error. Ensure the SDK feature is explicitly enabled in the settings (option vczapi_set_sdk_feature_parent).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Video Conferencing with Zoom plugin for WordPress fails to perform authorization checks on the 'get_auth' AJAX action, which is exposed to unauthenticated users. An attacker can obtain the site's Zoom SDK API key and a freshly-signed JWT signature by using a publicly available nonce, allowing them to join any Zoom meeting associated with the credentials.

Vulnerable Code

// includes/admin/class-zvc-admin-ajax.php:23
add_action('wp_ajax_nopriv_get_auth', array($this, 'get_auth'));
add_action('wp_ajax_get_auth', array($this, 'get_auth'));

---

// includes/admin/class-zvc-admin-ajax.php:183
public function get_auth()
{
    check_ajax_referer('_nonce_zvc_security', 'noncce');
    $meeting_id = filter_input(INPUT_POST, 'meeting_id');
    if (vczapi_is_sdk_enabled()) {
        $sdk_key    = get_option('vczapi_sdk_key');
        $secret_key = get_option('vczapi_sdk_secret_key');
        $signature  = $this->generate_sdk_signature($sdk_key, $secret_key, $meeting_id, 0);
        wp_send_json_success(['sig' => $signature, 'key' => $sdk_key, 'type' => 'sdk']);
    } else {
        wp_send_json_error('Error occured!');
    }

    wp_die();
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.7/assets/vendor/zoom/websdk/zoom-meeting.bundle.js /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.8/assets/vendor/zoom/websdk/zoom-meeting.bundle.js
--- /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.7/assets/vendor/zoom/websdk/zoom-meeting.bundle.js	2024-09-26 08:39:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.8/assets/vendor/zoom/websdk/zoom-meeting.bundle.js	2026-06-09 07:25:54.000000000 +0000
@@ -1 +1 @@
-"use strict";(self.webpackChunkvideo_conferencing_with_zoom_api=self.webpackChunkvideo_conferencing_with_zoom_api||[]).push([[721],{631:(e,n,t)=>{var i=t(114);const o={meetingID:atob(zvc_ajx.meeting_id),redirectTo:zvc_ajx.redirect_page,password:!1!==zvc_ajx.meeting_pwd&&atob(zvc_ajx.meeting_pwd),infoContainer:document.querySelector(".vczapi-zoom-browser-meeting--info__browser"),init:function(){this.initSDK(),this.eventHandlers(),zvc_ajx.enable_direct_join_via_browser&&this.handleJoinOnInit()},initSDK:function(){i.ZoomMtg.preLoadWasm(),i.ZoomMtg.prepareWebSDK()},eventHandlers:function(){let e=document.getElementById("vczapi-zoom-browser-meeting-join-mtg");null!=e&&(e.onclick=this.handleJoinMeetingButton.bind(this))},handleJoinOnInit:function(){const e=zvc_ajx.user_name,n=zvc_ajx.user_mail,t=this.password;this.handleJoinMeeting(e,t,n)},loader:function(){const e=document.createElement("span");return e.id="zvc-cover",e},generateSignature:async function(){const e=new FormData;return e.append("action","get_auth"),e.append("noncce",zvc_ajx.zvc_security),e.append("meeting_id",parseInt(this.meetingID)),(await fetch(zvc_ajx.ajaxurl,{method:"POST",body:e})).json()},removeLoader:function(){null!==document.getElementById("zvc-cover")&&document.getElementById("zvc-cover").remove()},handleJoinMeeting:function(e,n,t,i){null==this.meetingID&&""===this.meetingID||this.generateSignature().then((o=>{if(o.success){document.getElementById("zmmtg-root").style.display="block",this.removeLoader();const a={name:null!==e?e:"",password:null!==n?n:"",email:null!==t?t:"",locale:i};this.prepBeforeJoin(o,a)}}))},handleJoinMeetingButton:function(e){e.preventDefault(),document.body.appendChild(this.loader());const n=document.getElementById("vczapi-jvb-display-name"),t=document.getElementById("vczapi-jvb-email"),i=document.getElementById("meeting_password"),o=document.querySelector(".meeting-locale");if(null!==n&&(null===n.value||""===n.value))return this.infoContainer.innerHTML="Name is a Required field!",this.infoContainer.style.color="red",this.removeLoader(),!1;if(null!==t&&(null===t.value||""===t.value))return this.infoContainer.innerHTML="Email is a Required field!",this.infoContainer.style.color="red",this.removeLoader(),!1;if(null!==i&&(null===i.value||""===i.value))return this.infoContainer.innerHTML="Validation: Password is Required!",this.infoContainer.style.color="red",this.removeLoader(),!1;const a=null!==n?n.value:"",r=null!==i?i.value:"",l=null!==t?t.value:"",s=null!==o.value?o.value:"en-US";this.handleJoinMeeting(a,r,l,s)},prepBeforeJoin:function(e,n){const t=e.data.key,i=e.data.sig,o=e.data.type,a=document.getElementById("vczapi-zoom-browser-meeting");null!==a&&a.remove();const r={lang:n.locale,leaveUrl:this.redirectTo};let l={meetingNumber:parseInt(this.meetingID),userName:n.name,signature:i,userEmail:n.email,passWord:n.password?n.password:this.password,success:function(e){console.log("Join Meeting Success")},error:function(e){console.log(e)}};const s=new URLSearchParams(window.location.search),c=Object.fromEntries(s.entries());null!==c.tk&&(l.tk=c.tk),window.location!==window.parent.location&&(r.leaveUrl=window.location.href),"jwt"===o?l.apiKey=t:"sdk"===o&&(l.sdkKey=t),this.joinMeeting(r,l)},joinMeeting:function(e,n){i.ZoomMtg.i18n.load(e.lang),i.ZoomMtg.init({leaveUrl:e.leaveUrl,isSupportAV:!0,meetingInfo:zvc_ajx.meetingInfo,disableInvite:zvc_ajx.disableInvite,disableRecord:zvc_ajx.disableRecord,disableJoinAudio:zvc_ajx.disableJoinAudio,isSupportChat:zvc_ajx.isSupportChat,isSupportQA:zvc_ajx.isSupportQA,isSupportBreakout:zvc_ajx.isSupportBreakout,isSupportCC:zvc_ajx.isSupportCC,screenShare:zvc_ajx.screenShare,success:function(){i.ZoomMtg.join(n)},error:function(e){console.log(e)}})}};document.addEventListener("DOMContentLoaded",o.init())}},e=>{e(e.s=631)}]);
\ No newline at end of file
+"use strict";(self.webpackChunkvideo_conferencing_with_zoom_api=self.webpackChunkvideo_conferencing_with_zoom_api||[]).push([[721],{631:(e,n,t)=>{var i=t(114);const o={meetingID:atob(zvc_ajx.meeting_id),redirectTo:zvc_ajx.redirect_page,password:!1!==zvc_ajx.meeting_pwd&&atob(zvc_ajx.meeting_pwd),infoContainer:document.querySelector(".vczapi-zoom-browser-meeting--info__browser"),init:function(){this.initSDK(),this.eventHandlers(),zvc_ajx.enable_direct_join_via_browser&&this.handleJoinOnInit()},initSDK:function(){i.ZoomMtg.preLoadWasm(),i.ZoomMtg.prepareWebSDK()},eventHandlers:function(){let e=document.getElementById("vczapi-zoom-browser-meeting-join-mtg");null!=e&&(e.onclick=this.handleJoinMeetingButton.bind(this))},handleJoinOnInit:function(){const e=zvc_ajx.user_name,n=zvc_ajx.user_mail,t=this.password;this.handleJoinMeeting(e,t,n)},loader:function(){const e=document.createElement("span");return e.id="zvc-cover",e},generateSignature:async function(){const e=new FormData;return e.append("action","get_auth"),e.append("noncce",zvc_ajx.zvc_security),e.append("meeting_id",parseInt(this.meetingID)),(await fetch(zvc_ajx.ajaxurl,{method:"POST",body:e,credentials:"same-origin"})).json()},removeLoader:function(){null!==document.getElementById("zvc-cover")&&document.getElementById("zvc-cover").remove()},handleJoinMeeting:function(e,n,t,i){null==this.meetingID&&""===this.meetingID||this.generateSignature().then((o=>{if(o.success){document.getElementById("zmmtg-root").style.display="block",this.removeLoader();const a={name:null!==e?e:"",password:null!==n?n:"",email:null!==t?t:"",locale:i};this.prepBeforeJoin(o,a)}}))},handleJoinMeetingButton:function(e){e.preventDefault(),document.body.appendChild(this.loader());const n=document.getElementById("vczapi-jvb-display-name"),t=document.getElementById("vczapi-jvb-email"),i=document.getElementById("meeting_password"),o=document.querySelector(".meeting-locale");if(null!==n&&(null===n.value||""===n.value))return this.infoContainer.innerHTML="Name is a Required field!",this.infoContainer.style.color="red",this.removeLoader(),!1;if(null!==t&&(null===t.value||""===t.value))return this.infoContainer.innerHTML="Email is a Required field!",this.infoContainer.style.color="red",this.removeLoader(),!1;if(null!==i&&(null===i.value||""===i.value))return this.infoContainer.innerHTML="Validation: Password is Required!",this.infoContainer.style.color="red",this.removeLoader(),!1;const a=null!==n?n.value:"",r=null!==i?i.value:"",l=null!==t?t.value:"",s=null!==o.value?o.value:"en-US";this.handleJoinMeeting(a,r,l,s)},prepBeforeJoin:function(e,n){const t=e.data.sig,i=document.getElementById("vczapi-zoom-browser-meeting");null!==i&&i.remove();const o={lang:n.locale,leaveUrl:this.redirectTo};let a={meetingNumber:parseInt(this.meetingID),userName:n.name,signature:t,userEmail:n.email,passWord:n.password?n.password:this.password,success:function(e){console.log("Join Meeting Success")},error:function(e){console.log(e)}};const r=new URLSearchParams(window.location.search),l=Object.fromEntries(r.entries());null!==l.tk&&(a.tk=l.tk),window.location!==window.parent.location&&(o.leaveUrl=window.location.href),this.joinMeeting(o,a)},joinMeeting:function(e,n){i.ZoomMtg.i18n.load(e.lang),i.ZoomMtg.init({leaveUrl:e.leaveUrl,isSupportAV:!0,meetingInfo:zvc_ajx.meetingInfo,disableInvite:zvc_ajx.disableInvite,disableRecord:zvc_ajx.disableRecord,disableJoinAudio:zvc_ajx.disableJoinAudio,isSupportChat:zvc_ajx.isSupportChat,isSupportQA:zvc_ajx.isSupportQA,isSupportBreakout:zvc_ajx.isSupportBreakout,isSupportCC:zvc_ajx.isSupportCC,screenShare:zvc_ajx.screenShare,success:function(){i.ZoomMtg.join(n)},error:function(e){console.log(e)}})}};document.addEventListener("DOMContentLoaded",o.init())}},e=>{e(e.s=631)}]);
\ No newline at end of file
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.7/includes/admin/class-zvc-admin-ajax.php /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.8/includes/admin/class-zvc-admin-ajax.php
--- /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.7/includes/admin/class-zvc-admin-ajax.php	2026-04-20 06:57:08.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/video-conferencing-with-zoom-api/4.6.8/includes/admin/class-zvc-admin-ajax.php	2026-06-09 07:25:54.000000000 +0000
@@ -180,15 +182,40 @@
 	 */
 	public function get_auth()
 	{
-		check_ajax_referer('_nonce_zvc_security', 'noncce');
... (truncated)

Exploit Outline

1. Navigate to any page on the target site that displays a Zoom meeting (triggering the 'Join via Browser' scripts). 2. Extract the AJAX nonce from the frontend HTML or the global JavaScript object `window.zvc_ajx.zvc_security`. 3. Identify a valid Zoom meeting ID associated with the site. 4. Send an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the parameters `action=get_auth`, `noncce=<EXTRACTED_NONCE>`, and `meeting_id=<MEETING_ID>`. 5. Capture the JSON response, which contains the site's Zoom SDK API Key and a signed JWT signature for the provided meeting ID. 6. Use these credentials with the Zoom Web SDK to join the target meeting.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.