Headline
CVE-2023-2171: badgeos_achievement.php in badgeos/trunk/includes/shortcodes – WordPress Plugin Repository
The BadgeOS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin’s shortcode(s) in versions up to, and including, 3.7.1.6 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers with contributor-level and above permissions to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
1<?php23/**4 * Register the [badgeos_achievement] shortcode.5 *6 * @since 1.4.07 */8function badgeos_register_achievement_shortcode() {910 $achievements = badgeos_get_achievements_id_title_pair();11 badgeos_register_shortcode( array(12 ‘name’ => __( 'Single Achievement’, ‘badgeos’ ),13 ‘slug’ => 'badgeos_achievement’,14 ‘output_callback’ => 'badgeos_achievement_shortcode’,15 ‘description’ => __( 'Render a single achievement.’, ‘badgeos’ ),16 ‘attributes’ => array(17 ‘id’ => array(18 ‘name’ => __( 'Achievement ID’, ‘badgeos’ ),19 ‘description’ => __( 'The ID of the achievement to render.’, ‘badgeos’ ),20 ‘type’ => 'select’,21 ‘values’ => $achievements,22 ‘default’ => '’,23 ),24 ‘show_title’ => array (25 ‘name’ => __( 'Show Title’, ‘badgeos’ ),26 ‘description’ => __( 'Display Achievement Title.’, ‘badgeos’ ),27 ‘type’ => 'select’,28 ‘values’ => array (29 ‘true’ => __( 'True’, ‘badgeos’ ),30 ‘false’ => __( 'False’, ‘badgeos’ )31 ),32 ‘default’ => 'true’,33 ),34 ‘show_thumb’ => array (35 ‘name’ => __( 'Show Thumbnail’, ‘badgeos’ ),36 ‘description’ => __( 'Display Thumbnail Image.’, ‘badgeos’ ),37 ‘type’ => 'select’,38 ‘values’ => array(39 ‘true’ => __( 'True’, ‘badgeos’ ),40 ‘false’ => __( 'False’, ‘badgeos’ )41 ),42 ‘default’ => 'true’,43 ),44 ‘show_description’ => array (45 ‘name’ => __( 'Show Description’, ‘badgeos’ ),46 ‘description’ => __( 'Display Short Description.’, ‘badgeos’ ),47 ‘type’ => 'select’,48 ‘values’ => array(49 ‘true’ => __( 'True’, ‘badgeos’ ),50 ‘false’ => __( 'False’, ‘badgeos’ )51 ),52 ‘default’ => 'true’,53 ),54 ‘show_steps’ => array (55 ‘name’ => __( 'Show Steps’, ‘badgeos’ ),56 ‘description’ => __( 'Display Steps after the Description.’, ‘badgeos’ ),57 ‘type’ => 'select’,58 ‘values’ => array(59 ‘true’ => __( 'True’, ‘badgeos’ ),60 ‘false’ => __( 'False’, ‘badgeos’ )61 ),62 ‘default’ => 'true’,63 ),64 ‘image_width’ => array (65 ‘name’ => __( 'Thumnail Width’, ‘badgeos’ ),66 ‘description’ => __( "Achievement’s image width.", ‘badgeos’ ),67 ‘type’ => 'text’,68 ‘default’ => '’,69 ),70 ‘image_height’ => array (71 ‘name’ => __( 'Thumnail Height’, ‘badgeos’ ),72 ‘description’ => __( "Achievement’s image height.", ‘badgeos’ ),73 ‘type’ => 'text’,74 ‘default’ => '’,75 ),76 ),77 ) );78}79add_action( 'init’, ‘badgeos_register_achievement_shortcode’ );8081/**82 * Single Achievement Shortcode.83 *84 * @since 1.0.085 *86 * @param array $atts Shortcode attributes.87 * @return string HTML markup.88 */89function badgeos_achievement_shortcode( $atts = array() ) {90 global $wpdb;91 // get the post id92 $atts = shortcode_atts( array(93 ‘id’ => '’,94 ‘show_title’ => 'true’,95 ‘show_thumb’ => 'true’,96 ‘show_description’ => 'true’,97 ‘show_steps’ => 'true’,98 ‘image_width’ => '’,99 ‘image_height’ => '’,100 ), $atts, ‘badgeos_achievement’ );101102 // return if post id not specified103 $settings = ( $exists = badgeos_utilities::get_option( ‘badgeos_settings’ ) ) ? $exists : array();104 if ( empty($atts[‘id’]) ) {105 $achievements = $wpdb->get_results( $wpdb->prepare( "select * from “.$wpdb->prefix."badgeos_achievements where post_type!=%s and user_id=%d order by actual_date_earned desc limit 1", trim( $settings[‘achievement_step_post_type’] ), get_current_user_id() ) );106 if( count( $achievements ) > 0 ) {107 $atts[‘id’] = $achievements[0]->ID;108 }109 }110111 // return if post id not specified112 if ( empty($atts[‘id’]) )113 return;114115 wp_enqueue_style( ‘badgeos-front’ );116 wp_enqueue_script( ‘badgeos-achievements’ );117118 // get the post content and format the badge display119 $achievement = badgeos_utilities::badgeos_get_post( $atts[‘id’] );120 $output = '’;121122 // If we’re dealing with an achievement post123 if ( badgeos_is_achievement( $achievement ) ) {124 $output .= '<div id="badgeos-single-achievement-container-'.$atts[‘id’].’” class="badgeos-single-achievement badgeos-single-achievement-'.$atts[‘id’].’">’; // necessary for the jquery click handler to be called125 $output .= badgeos_render_achievement( $achievement, $atts[‘show_title’], $atts[‘show_thumb’], $atts[‘show_description’], $atts[‘show_steps’], $atts[‘image_width’], $atts[‘image_height’] );126 $output .= '</div>’;127 }128129 // Return our rendered achievement130 return $output;131}