rtMedia for WordPress, BuddyPress and bbPress <= 4.7.9 - Missing Authorization
Description
The rtMedia for WordPress, BuddyPress and bbPress plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 4.7.9. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=4.7.9What Changed in the Fix
Changes introduced in v4.7.10
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-40773 (rtMedia Missing Authorization) ## 1. Vulnerability Summary The **rtMedia** plugin for WordPress is vulnerable to **Missing Authorization** in its AJAX media deletion handler. The function `rtmedia_delete_uploaded_media()` in `app/main/controllers/templa…
Show full research plan
Exploitation Research Plan: CVE-2026-40773 (rtMedia Missing Authorization)
1. Vulnerability Summary
The rtMedia plugin for WordPress is vulnerable to Missing Authorization in its AJAX media deletion handler. The function rtmedia_delete_uploaded_media() in app/main/controllers/template/rtmedia-ajax-actions.php verifies a WordPress nonce but fails to check:
- If the current user has the capability to delete media (e.g.,
delete_posts). - If the
media_idprovided in the request actually belongs to the current user (Insecure Direct Object Reference - IDOR).
As a result, any authenticated user (Subscriber and above) can delete any media uploaded via rtMedia (photos, videos, music) by providing their own valid nonce and the target media_id.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
delete_uploaded_media(hooked viawp_ajax_delete_uploaded_media) - HTTP Method:
POST - Parameters:
action:delete_uploaded_mediamedia_id: The ID of the rtMedia entry to delete.nonce: A nonce valid for the action string'rtmedia_' . get_current_user_id().
- Authentication: Required (Subscriber level or higher).
- Preconditions: The attacker must be able to obtain a valid nonce for themselves, which the plugin provides on pages where the media gallery is loaded.
3. Code Flow
- Entry Point: The user sends a POST request to
admin-ajax.phpwithaction=delete_uploaded_media. - Hook Registration:
app/main/controllers/template/rtmedia-ajax-actions.phpregisters the handler:add_action( 'wp_ajax_delete_uploaded_media', 'rtmedia_delete_uploaded_media' ); - Parameter Extraction: Inside
rtmedia_delete_uploaded_media():$nonceis taken from$_POST['nonce'].$media_idis taken from$_POST['media_id'].
- Nonce Verification:
This verifies that the nonce was generated for the current user. It does not verify that the user has permission to delete the specificif ( wp_verify_nonce( $nonce, 'rtmedia_' . get_current_user_id() ) ) {$media_id. - Vulnerable Sink:
The$rtmedia_media = new RTMediaMedia(); $rtmedia_media->delete( $media_id );delete()method is called directly with the user-suppliedmedia_id, leading to unauthorized deletion of media belonging to other users.
4. Nonce Acquisition Strategy
The nonce is generated per-user using the action string 'rtmedia_' . get_current_user_id(). This nonce is localized and passed to the frontend for the plugin's legitimate delete functionality.
- Identify Trigger: rtMedia enqueues its scripts on pages containing the
[rtmedia_gallery]shortcode or on BuddyPress profile media tabs. - Shortcode Creation: Create a public page with the gallery shortcode to ensure the scripts load for the Subscriber.
wp post create --post_type=page --post_status=publish --post_title="Media" --post_content="[rtmedia_gallery]"
- Extraction: Navigate to this page as the Subscriber and use
browser_evalto extract the nonce from thertmedia_ajax_paramsglobal object.- JS Variable:
window.rtmedia_ajax_params - Nonce Key:
nonce - Command:
browser_eval("window.rtmedia_ajax_params ? window.rtmedia_ajax_params.nonce : 'not_found'")
- JS Variable:
5. Exploitation Strategy
Step 1: Target Identification
As an Admin, upload a media file and identify its rtMedia ID. rtMedia uses its own database table (wp_rt_rtm_media).
# Get the ID of the latest uploaded rtMedia entry
wp db query "SELECT id FROM wp_rt_rtm_media ORDER BY id DESC LIMIT 1;"
Step 2: Nonce Retrieval
Log in as the Subscriber, navigate to the media page, and extract the nonce using the strategy in Section 4.
Step 3: Unauthorized Deletion Request
Use the http_request tool to send the malicious payload.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=delete_uploaded_media&nonce=[SUBSCRIBER_NONCE]&media_id=[TARGET_MEDIA_ID]
Step 4: Verification
Confirm the deletion using WP-CLI.
6. Test Data Setup
- Users:
- Admin:
admin/password - Subscriber:
attacker/password
- Admin:
- Content:
- Create a page for nonce extraction:
[rtmedia_gallery]. - The Admin must upload at least one image via the rtMedia interface (e.g., via the BuddyPress profile or a gallery page) so there is a
media_idto target. - Note: Ensure BuddyPress is active or the rtMedia "Allow upload from WordPress author page" setting is enabled to facilitate the upload.
- Create a page for nonce extraction:
7. Expected Results
- AJAX Response:
{ "success": true, "data": { "code": "rtmedia-media-deleted", ... } } - Database State: The record with
id = [TARGET_MEDIA_ID]should be removed from thewp_rt_rtm_mediatable. - Filesystem State: The associated attachment file in
wp-content/uploads/(if it was the primary media) should be deleted or detached.
8. Verification Steps
- Check Table:
The count should bewp db query "SELECT count(*) FROM wp_rt_rtm_media WHERE id = [TARGET_MEDIA_ID];"0. - Check Attachment:
Check if the WordPress attachment associated with that media ID (if any) still exists.
9. Alternative Approaches
If rtmedia_ajax_params is not found, check for:
rtMedia_plupload_config.multipart_params.nonce- Searching the entire page source for the string
rtmedia_followed by the current user ID to see how the nonce is assigned to HTML attributes (e.g.,data-nonceon a delete button). - If the
rtmedia_user ID nonce is not present, check if the plugin accidentally falls back to a default nonce for action-1in certain configurations.
Summary
The rtMedia plugin for WordPress is vulnerable to unauthorized media deletion due to a missing authorization check and an insecure direct object reference (IDOR) in its AJAX handler. This allows authenticated attackers with subscriber-level permissions to delete any media uploaded through the plugin by supplying a valid nonce tied to their own user ID and a target media ID.
Vulnerable Code
// app/main/controllers/template/rtmedia-ajax-actions.php line 12 function rtmedia_delete_uploaded_media() { $action = sanitize_text_field( filter_input( INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ); $nonce = sanitize_text_field( filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ); $media_id = filter_input( INPUT_POST, 'media_id', FILTER_SANITIZE_NUMBER_INT ); if ( ! empty( $action ) && 'delete_uploaded_media' === $action && ! empty( $media_id ) ) { if ( wp_verify_nonce( $nonce, 'rtmedia_' . get_current_user_id() ) ) { $remaining_album = 0; $remaining_photos = 0; $remaining_music = 0; $remaining_videos = 0; $remaining_all_media = 0; $rtmedia_media = new RTMediaMedia(); $rtmedia_media->delete( $media_id );
Security Fix
@@ -7,7 +7,7 @@ /** * Delete uploaded media. - * Modified 10-02-2019 by Adarsh Verma <adarsh.verma@rtcamp.com> + * Patched to include Ownership and Authorization checks. */ function rtmedia_delete_uploaded_media() { @@ -17,6 +17,47 @@ if ( ! empty( $action ) && 'delete_uploaded_media' === $action && ! empty( $media_id ) ) { if ( wp_verify_nonce( $nonce, 'rtmedia_' . get_current_user_id() ) ) { + + $model = new RTMediaModel(); + $media = $model->get( array( 'id' => $media_id ) ); + + // Check if media exists + if ( empty( $media ) || ! isset( $media[0] ) ) { + wp_send_json_error( + array( + 'code' => 'rtmedia-media-not-found', + 'message' => esc_html__( 'Media not found.', 'buddypress-media' ), + ) + ); + wp_die(); + } + + $current_user_id = get_current_user_id(); + $media_author = (int) $media[0]->media_author; + + // 1. Is the user the owner of the media? + $is_owner = ( $current_user_id === $media_author ); + + // 2. Is the user a site administrator? + $is_admin = current_user_can( 'manage_options' ) || current_user_can( 'delete_others_posts' ); + + // 3. Is the user a BuddyPress Group Admin? (if the media belongs to a BP group) + $is_group_admin = false; + if ( ! empty( $media[0]->context ) && 'group' === $media[0]->context && function_exists( 'groups_is_user_admin' ) ) { + $is_group_admin = groups_is_user_admin( $current_user_id, $media[0]->context_id ); + } + + // If none of the above are true, block the deletion + if ( ! $is_owner && ! $is_admin && ! $is_group_admin ) { + wp_send_json_error( + array( + 'code' => 'rtmedia-unauthorized', + 'message' => esc_html__( 'You do not have permission to delete this media.', 'buddypress-media' ), + ) + ); + wp_die(); + } + $remaining_album = 0; $remaining_photos = 0; $remaining_music = 0; @@ -29,7 +70,6 @@ if ( class_exists( 'RTMediaNav' ) ) { global $bp; $rtmedia_nav_obj = new RTMediaNav(); - $model = new RTMediaModel(); $other_count = 0; if ( function_exists( 'bp_is_group' ) && bp_is_group() ) {
Exploit Outline
1. Authentication: Log in to the WordPress site as a Subscriber-level user. 2. Nonce Acquisition: Navigate to any page where rtMedia is active (e.g., a page with the `[rtmedia_gallery]` shortcode). Extract the security nonce from the global JavaScript object `rtmedia_ajax_params.nonce`. 3. Target Identification: Identify the `media_id` of a target media file (uploaded by an administrator or another user) within the `wp_rt_rtm_media` table or by inspecting gallery links. 4. Unauthorized Request: Send a POST request to `/wp-admin/admin-ajax.php` with the following body: - `action`: `delete_uploaded_media` - `nonce`: [Your extracted nonce] - `media_id`: [The target ID] 5. Verification: The plugin verifies the nonce against the attacker's user ID but performs no ownership check, resulting in the deletion of the target media file and its database record.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.