rtMedia for WordPress, BuddyPress and bbPress <= 4.7.8 - Unauthenticated Information Exposure
Description
The rtMedia for WordPress, BuddyPress and bbPress plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 4.7.8. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=4.7.8What Changed in the Fix
Changes introduced in v4.7.9
Source Code
WordPress.org SVN### 1. Vulnerability Summary The **rtMedia for WordPress, BuddyPress and bbPress** plugin (versions <= 4.7.8) contains an unauthenticated information exposure vulnerability. The plugin fails to properly restrict access to certain REST API endpoints or frontend localized variables that contain sensit…
Show full research plan
1. Vulnerability Summary
The rtMedia for WordPress, BuddyPress and bbPress plugin (versions <= 4.7.8) contains an unauthenticated information exposure vulnerability. The plugin fails to properly restrict access to certain REST API endpoints or frontend localized variables that contain sensitive configuration data. Specifically, site-wide options (including third-party API keys, license information, and server paths) or private media metadata can be extracted by an unauthenticated attacker.
The vulnerability stems from inadequate permission checks in the RTMediaRestAPI (registered via app/main/controllers/api/RTMediaRestAPI.php) and the excessive exposure of the global $rtmedia->options array in frontend JavaScript localization.
2. Attack Vector Analysis
- Endpoints:
- REST API:
/wp-json/rtmedia/v1/settingsor/wp-json/rtmedia/v1/support. - Frontend: Any public-facing page where rtMedia scripts are enqueued (e.g., activity feed, media gallery pages).
- REST API:
- Authentication: None required (Unauthenticated).
- Parameter:
rtmedia_config(JavaScript variable) or direct GET requests to REST routes. - Preconditions: The plugin must be active. For JavaScript-based leaks, a page with an rtMedia shortcode (e.g.,
[rtmedia_gallery]) or the BuddyPress Activity page must be publicly accessible.
3. Code Flow
- Initialization: In
index.php, the global$rtmediaobject is instantiated ($rtmedia = new RTMedia();). - Option Loading: In
app/admin/RTMediaUploadTermsAdmin.php(and other components), the plugin frequently loads the entirertmedia-optionssite option:$rtmedia->options = rtmedia_get_site_option( 'rtmedia-options' ); - Localization: The plugin enqueues the main frontend script (
rtmedia-main) and localizes configuration data for use in the browser. In theRTMediamain class,wp_localize_scriptis called to pass values tortmedia_config. If this call includes theoptionsarray without filtering sensitive keys, it is exposed in the HTML source. - REST API: The
RTMediaRestAPIclass registers routes duringrest_api_init. If endpoints designed for debugging or settings do not implement apermission_callbackchecking formanage_options, any unauthenticated user can query them.
4. Nonce Acquisition Strategy
While many REST endpoints in rtMedia require a nonce for modifying data, many information exposure vulnerabilities in this plugin involve GET requests that either omit the nonce check or use the standard wp_rest nonce which is often publicly exposed.
To obtain the rtmedia_config data (including nonces if present):
- Identify Page: Identify a page where rtMedia is active. If BuddyPress is installed, the
/activity/page is the primary target. - Create Test Page: If no public page exists, create one with the gallery shortcode:
wp post create --post_type=page --post_title="Media" --post_status=publish --post_content='[rtmedia_gallery]' - Extract Variable: Use
browser_navigateto the page andbrowser_evalto extract the configuration object:// Target the main rtMedia config object browser_eval("window.rtmedia_config")
5. Exploitation Strategy
The goal is to extract the rtmedia-options array, which may contain sensitive keys.
Step 1: Probe REST API (Settings/Support)
Check for unrestricted access to configuration endpoints.
- Request:
GET /wp-json/rtmedia/v1/support - Alternative Request:
GET /wp-json/rtmedia/v1/settings - Tool:
http_request
Step 2: Extract Frontend Configuration
If REST is restricted, extract the data via the localized script variable.
- Action: Navigate to the homepage or a page with
[rtmedia_gallery]. - Tool:
browser_navigatefollowed bybrowser_eval("window.rtmedia_config"). - Target Data: Look for
rtmedia_config.optionsorrtmedia_config.api_config.
Step 3: Check for Media Metadata Leak
Check if private media metadata (ID, title, owner) can be listed without authentication.
- Request:
GET /wp-json/rtmedia/v1/media?per_page=10 - Tool:
http_request
6. Test Data Setup
- Install rtMedia and BuddyPress: Ensure the plugin is active.
- Populate Dummy Sensitive Data: Add a fake S3 key or transcoding secret to the options:
wp option patch update rtmedia-options s3_secret_key "EXPLOIT_SUCCESS_S3_KEY" wp option patch update rtmedia-options transcoding_api_key "EXPLOIT_SUCCESS_TRANSCODING_KEY" - Create Private Media: Upload a media item and set its privacy to
60(Private).# Note: Requires a user ID, assuming 1 wp eval "rtmedia_db_insert(array('media_id' => 123, 'privacy' => 60, 'media_title' => 'SENSITIVE_LEAK_TITLE', 'media_type' => 'photo'));"
7. Expected Results
- REST API: The response should return a JSON object containing the
rtmedia-optionsor system debug information. - JS Extraction: The
rtmedia_configobject in the console should contain thes3_secret_keyor other configuration parameters. - Media Leak: The response from
/wp-json/rtmedia/v1/mediashould include the entry with the titleSENSITIVE_LEAK_TITLEdespite it being private.
8. Verification Steps
- Verify S3 Key Exposure:
# Run after HTTP request # If the response contains "EXPLOIT_SUCCESS_S3_KEY", vulnerability is confirmed. - Check User Exposure: Verify if the leaked REST API data contains user emails or internal file paths (e.g.,
ABSPATH).
9. Alternative Approaches
If /wp-json/rtmedia/v1/ is blocked, try:
- AJAX Endpoint:
POST /wp-admin/admin-ajax.phpwithaction=rtmedia_get_support_data. - Shortcode-based Exposure: Some shortcodes render attributes directly into the page source without escaping. Check
[rtmedia_gallery]output for hidden attributes or metadata in JSON blobs. - **Transcoding
Summary
The rtMedia plugin for WordPress (<= 4.7.8) is vulnerable to unauthenticated information exposure through an AJAX endpoint in its GoDAM integration. The plugin registered a public AJAX action that lacked both authentication and proper permission checks, allowing unauthorized users to retrieve and view private BuddyPress activity comments.
Vulnerable Code
// templates/media/godam-integration.php /** * Handle AJAX request for loading a single activity comment's HTML. */ add_action( 'wp_ajax_get_single_activity_comment_html', 'handle_get_single_activity_comment_html' ); add_action( 'wp_ajax_nopriv_get_single_activity_comment_html', 'handle_get_single_activity_comment_html' ); // Line 187 /** * AJAX handler to fetch and return the HTML for a single activity comment. * * Validates the request, loads the activity comment by ID, * renders its HTML using the BuddyPress template, and returns it in a JSON response. * * @return void Outputs JSON response with rendered HTML or error message. */ function handle_get_single_activity_comment_html() { // Line 198 check_ajax_referer( 'godam-ajax-nonce', 'nonce' ); $activity_id = isset( $_POST['comment_id'] ) ? intval( $_POST['comment_id'] ) : 0; if ( ! $activity_id ) { wp_send_json_error( 'Invalid activity ID' ); } $activity = new BP_Activity_Activity( $activity_id ); if ( empty( $activity->id ) ) { wp_send_json_error( 'Activity comment not found' ); } global $activities_template; // ... (truncated)
Security Fix
@@ -37,8 +37,7 @@ * Constructing settings for upload terms. */ public function __construct() { - $this->upload_terms_message = esc_html__( 'terms of services.', 'buddypress-media' ); - $this->upload_terms_error_message = esc_html__( 'Please check terms of service.', 'buddypress-media' ); + add_action( 'init', array( $this, 'init_translations' ), 5 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ), 999 ); add_filter( 'rtmedia_general_content_default_values', array( $this, 'add_admin_option_default_value' ), 10, 1 ); @@ -47,6 +46,14 @@ } /** + * Initialize translations at the proper time. + */ + public function init_translations() { + $this->upload_terms_message = esc_html__( 'terms of services.', 'buddypress-media' ); + $this->upload_terms_error_message = esc_html__( 'Please check terms of service.', 'buddypress-media' ); + } + + /** * Loads styles and scripts * * @global object $rtmedia @@ -183,14 +186,15 @@ /** * Handle AJAX request for loading a single activity comment's HTML. + * Note: Only registered for logged-in users (wp_ajax_) for security. */ add_action( 'wp_ajax_get_single_activity_comment_html', 'handle_get_single_activity_comment_html' ); - add_action( 'wp_ajax_nopriv_get_single_activity_comment_html', 'handle_get_single_activity_comment_html' ); /** * AJAX handler to fetch and return the HTML for a single activity comment. * * Validates the request, loads the activity comment by ID, + * verifies the user has permission to view it, * renders its HTML using the BuddyPress template, and returns it in a JSON response. * * @return void Outputs JSON response with rendered HTML or error message. @@ -198,15 +202,25 @@ function handle_get_single_activity_comment_html() { check_ajax_referer( 'godam-ajax-nonce', 'nonce' ); + // Require user to be logged in. + if ( ! is_user_logged_in() ) { + wp_send_json_error( __( 'Authentication required', 'buddypress-media' ), 401 ); + } + $activity_id = isset( $_POST['comment_id'] ) ? intval( $_POST['comment_id'] ) : 0; if ( ! $activity_id ) { - wp_send_json_error( 'Invalid activity ID' ); + wp_send_json_error( __( 'Invalid activity ID', 'buddypress-media' ), 400 ); } $activity = new BP_Activity_Activity( $activity_id ); if ( empty( $activity->id ) ) { - wp_send_json_error( 'Activity comment not found' ); + wp_send_json_error( __( 'Activity comment not found', 'buddypress-media' ), 404 ); + } + + // Verify user has permission to view this activity. + if ( ! rtmedia_user_can_view_activity( $activity ) ) { + wp_send_json_error( __( 'You do not have permission to view this activity', 'buddypress-media' ), 403 ); } global $activities_template;
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker first identifies a valid `godam-ajax-nonce` by inspecting the page source or network traffic of any page where rtMedia's GoDAM integration scripts are enqueued. The attacker then sends an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `get_single_activity_comment_html`, the `nonce` parameter set to the intercepted value, and a `comment_id` parameter targeting a specific BuddyPress activity comment. Because the `nopriv` action is registered and the handler fails to perform authentication or group/profile privacy checks, the server returns the full rendered HTML content of the private comment in the JSON response.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.