CVE-2018-14071 (PHP, published 2018-07-16T13:29Z)
Description: value: The Geo Mashup plugin before 1.10.4 for WordPress has insufficient sanitization of post editor and other user input.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-20 \u2014 Improper Input Validation
The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Repository: https://github.com/cyberhobo/wordpress-geo-mashup
Files changed:
geo-mashup-db.php
geo-mashup-ui-managers.php
geo-mashup.php
geo-query.php
Commit message: Strengthen sanitization, fixes #817


Vulnerable code:
/** 
	 * 
		
		GeoMashup::register_script( 
				'mxn', 
				'js/mxn/mxn.js', 
				null, 
				GEO_MASHUP_VERSION , 
				
		GeoMashup::register_script( 
				'mxn-core', 
				'js/mxn/mxn.core.js', 
				array( 'mxn' ), 
				GEO_MASHUP_VERSION, 
					null, 
					'', 
					
			GeoMashup::register_script( 
					'mxn-google-3', 
					'js/mxn/mxn.googlev3.core.js', 
					array( 'mxn-core', 'google-maps-3' ), 
					GEO_MASHUP_VERSION, 
					
			GeoMashup::register_script( 
					'mxn-google-3-gm', 
					'js/mxn/mxn.googlev3.geo-mashup.js', 
					array( 'mxn-google-3' ), 
					GEO_MASHUP_VERSION, 
							
			wp_register_script( 
					'openlayers', 
					null, 
					'latest', 
					
			wp_register_script( 
					'openstreetmap', 
					 
			GeoMashup::register_script( 
					'js/mxn/mxn.openlayers.core.js', 
					array( 'mxn-core', 'openstreetmap' ), 
					GEO_MASHUP_VERSION, 
					
			GeoMashup::register_script( 
					'mxn-openlayers-gm', 
					'js/mxn/mxn.openlayers.geo-mashup.js', 
					array( 'mxn-openlayers' ), 
					GEO_MASHUP_VERSION, 
					
		GeoMashup::register_script( 
				'geo-mashup-location-editor', 
				'js/location-editor.js', 
				$required_scripts, 
				GEO_MASHUP_VERSION, 
				
		GeoMashup::register_script( 
				'jquery-ui-datepicker', 
				'js/jquery-ui.1.7.3.datepicker.js', 
				array( 'jquery', 'jquery-ui-core'), 
				'1.7.3', 
				
				wp_enqueue_script( 
					'geo-mashup-location-editor-custom', 
					$custom_url, 
	 * 
				 
	 * 
		
		if ( 'save' == $action or 'geocode' == $action ) {
			$date_string = $_POST['geo_mashup_date'] . ' ' . $_POST['geo_mashup_hour'] . ':' . 
				$_POST['geo_mashup_minute'] . ':00';
			$geo_date = date( 'Y-m-d H:i:s', strtotime( $date_string ) );
			// If PHP has added slashes, WP will do it again before saving
			$post_location['saved_name'] = stripslashes( $_POST['geo_mashup_location_name'] );
			if ( 'geocode' == $action ) {
				$status = GeoMashupDB::geocode( $_POST['geo_mashup_search'], $post_location );
				if ( $status != 200 ) {
					$post_location = array();
				}
			} else {
				if ( ! empty( $_POST['geo_mashup_select'] ) ) {
					$selected_items = explode( '|', $_POST['geo_mashup_select'] );
					$post_location = intval( $selected_items[0] );
				} else { 
					$post_location['id'] = $_POST['geo_mashup_location_id'];
					list( $lat, $lng ) = explode( ',', $_POST['geo_mashup_location'] );
					$post_location['lat'] = trim( $lat );
					$post_location['lng'] = trim( $lng );
					$post_location['geoname'] = $_POST['geo_mashup_geoname'];
					$post_location['address'] = stripslashes( $_POST['geo_mashup_address'] );
					$post_location['postal_code'] = $_POST['geo_mashup_postal_code'];
					$post_location['country_code'] = $_POST['geo_mashup_country_code'];
					$post_location['admin_code'] = $_POST['geo_mashup_admin_code'];
					$post_location['sub_admin_code'] = $_POST['geo_mashup_sub_admin_code'];
					$post_location['locality_name'] = $_POST['geo_mashup_locality_name'];
					if ( !empty( $_POST['geo_mashup_null_fields'] ) )
						$post_location['set_null'] = $_POST['geo_mashup_null_fields'];
				}
			}
			
			if ( ! empty( $post_location ) ) {
				$error = GeoMashupDB::set_object_location( $object_name, $object_id, $post_location, true, $geo_date );
				if ( is_wp_error( $error ) ) 
					return $error;
			}
		} else if ( 'delete' == $action ) {
			if ( is_wp_error( $error ) ) 
				return $error;
		// If geodata was manually updated but Geo Mashup location was not,
		// they may be out of sync now. Allowing that for now.
		return true;
	 * 
	 * @global array $geo_mashup_options 
		if ( $enabled ) { 
	 * 
			$object_id = $_GET['user_id'];
	 * 
	 * @return bool|WP_Error 
		$user_id = $_POST['user_id'];

		if ( !is_numeric( $user_id ) ) {
			return $user_id;
		}
	 * 
	 * 
	 * 
	 * @global array $geo_mashup_options 
		} 
	 * 
	 * 
	 * 
	 * @param id $post_id 
	 * @param object $post 
	 * 
	 * 
	 * @param array $shortcode_match 
		$tag_index = array_search( 'geo_mashup_save_location',  $shortcode_match ); 
		} 
	 * 
	 * 
		
	 * 
	 * If an upload is KML, put the URL in an option to be loaded in the response 
	 * 
	 * 
	 * 
	 * @global array $geo_mashup_options 
		$load_comment_editor = ( !is_admin() && $geo_mashup_options->get( 'overall', 'located_object_name', 'comment' ) == 'true' ); 
		if ( $user ) 
		printf( $input_format, 'lat', 'lat', $default_location->lat );
		printf( $input_format, 'lng', 'lng', $default_location->lng );
			GeoMashup::register_script( 
					'geo-mashup-comment-form', 
					'js/comment-form.js', 
					array( 'jquery' ), 
					GEO_MASHUP_VERSION, 
					
		GeoMashupDB::set_object_location( 'comment', $comment_id, $_POST['comment_location'] );
		if ( isset( $_REQUEST['callback'] ) )
			$json = $_REQUEST['callback'] . '(' . $json . ')';
		$json = GeoMashup::get_locations_json($_REQUEST);
			$json = $_REQUEST['callback'] . '(' . $json . ')';

Fixed code:
	/**
	 * Sanitize an array of query arguments.
	 *
	 * @param array $query_args
	 *
	 * @return array
	 */
	public static function sanitize_query_args( $query_args ) {
		array_walk_recursive($query_args, array( __CLASS__, 'sanitize_query_arg' ) );
		return $query_args;
	}

	/**
	 * Sanitize a single query argument.
	 *
	 * @param mixed $value May be modified.
	 * @param string $name
	 */
	public static function sanitize_query_arg( &$value, $name ) {
		switch ($name) {
			case 'minlat':
			case 'maxlat':
			case 'minlng':
			case 'maxlng':
			case 'near_lat':
			case 'near_lng':
			case 'radius_km':
			case 'radius_mi':
				$value = (float) $value;
				break;

			case 'map_cat':
			case 'object_ids':
				$value = preg_replace( '/[^0-9,]', '', $value );
				break;

			case 'map_post_type':
			case 'object_name':
				$value = sanitize_key( $value );
				break;

			case 'limit':
			case 'map_offset':
				$value = (int) $value;
				break;

			case 'suppress_filters':
				$value = (bool) $value;
				break;

			default:
				$value = sanitize_text_field( $value );
		}
	}

/**
	 *

		GeoMashup::register_script(
				'mxn',
				'js/mxn/mxn.js',
				null,
				GEO_MASHUP_VERSION ,

		GeoMashup::register_script(
				'mxn-core',
				'js/mxn/mxn.core.js',
				array( 'mxn' ),
				GEO_MASHUP_VERSION,
					null,
					'',

			GeoMashup::register_script(
					'mxn-google-3',
					'js/mxn/mxn.googlev3.core.js',
					array( 'mxn-core', 'google-maps-3' ),
					GEO_MASHUP_VERSION,

			GeoMashup::register_script(
					'mxn-google-3-gm',
					'js/mxn/mxn.googlev3.geo-mashup.js',
					array( 'mxn-google-3' ),
					GEO_MASHUP_VERSION,

			wp_register_script(
					'openlayers',
					null,
					'latest',

			wp_register_script(
					'openstreetmap',

			GeoMashup::register_script(
					'js/mxn/mxn.openlayers.core.js',
					array( 'mxn-core', 'openstreetmap' ),
					GEO_MASHUP_VERSION,

			GeoMashup::register_script(
					'mxn-openlayers-gm',
					'js/mxn/mxn.openlayers.geo-mashup.js',
					array( 'mxn-openlayers' ),
					GEO_MASHUP_VERSION,

		GeoMashup::register_script(
				'geo-mashup-location-editor',
				'js/location-editor.js',
				$required_scripts,
				GEO_MASHUP_VERSION,

		GeoMashup::register_script(
				'jquery-ui-datepicker',
				'js/jquery-ui.1.7.3.datepicker.js',
				array( 'jquery', 'jquery-ui-core'),
				'1.7.3',

				wp_enqueue_script(
					'geo-mashup-location-editor-custom',
					$custom_url,
	 *

	 *

		$post_location = array();
		$search_text = $geo_date = '';

		if ( 'save' === $action || 'geocode' === $action ) {

			$date_string = sanitize_text_field( $_POST['geo_mashup_date'] ) . ' ' .
			               (int) $_POST['geo_mashup_hour'] . ':' .
			               (int) $_POST['geo_mashup_minute'] . ':00';
			$geo_date    = date( 'Y-m-d H:i:s', strtotime( $date_string ) );

			$post_location['saved_name'] = sanitize_text_field( wp_unslash( $_POST['geo_mashup_location_name'] ) );

			$search_text = sanitize_text_field( $_POST['geo_mashup_search'] );
		}

		if ( 'geocode' === $action && ! GeoMashupDB::geocode( $search_text, $post_location ) ) {
		}
		if ( 'save' === $action && ! empty( $_POST['geo_mashup_select'] ) ) {
			$selected_items = explode( '|', $_POST['geo_mashup_select'] );
			$post_location  = empty( $selected_items ) ? 0 : (int) $selected_items[0];
		}

		if ( 'save' === $action && empty( $_POST['geo_mashup_select'] ) ) {
			$post_location['id'] = (int) $_POST['geo_mashup_location_id'];
			list( $lat, $lng ) = explode( ',', $_POST['geo_mashup_location'] );
			$post_location['lat']            = (float) $lat;
			$post_location['lng']            = (float) $lng;
			$post_location['geoname']        = sanitize_text_field( $_POST['geo_mashup_geoname'] );
			$post_location['address']        = sanitize_text_field( wp_unslash( $_POST['geo_mashup_address'] ) );
			$post_location['postal_code']    = sanitize_text_field( $_POST['geo_mashup_postal_code'] );
			$post_location['country_code']   = $this->sanitize_country_code( $_POST['geo_mashup_country_code'] );
			$post_location['admin_code']     = sanitize_text_field( $_POST['geo_mashup_admin_code'] );
			$post_location['sub_admin_code'] = sanitize_text_field( $_POST['geo_mashup_sub_admin_code'] );
			$post_location['locality_name']  = sanitize_text_field( $_POST['geo_mashup_locality_name'] );
			$post_location['set_null']       = $this->sanitize_null_fields( $_POST['geo_mashup_null_fields'] );
		}

		$error = null;
		if ( ! empty( $post_location ) ) {

			$error = GeoMashupDB::set_object_location(
				$object_name,
				$object_id,
				$post_location,
				true,
				$geo_date
			);

		}

		if ( 'delete' === $action ) {

		return is_wp_error( $error ) ? $error : true;
	}

	/**
	 * Sanitize country codes to two uppercase alpha characters.
	 *
	 * @param string $code
	 *
	 * @return string
	 */
	private function sanitize_country_code( $code ) {
		return substr( preg_replace( '/[^A-Z]/', '', $code), 0, 2 );
	}

	/**
	 * Sanitize null fields to null or a safe string.
	 *
	 * @param string $fields
	 *
	 * @return string
	 */
	private function sanitize_null_fields( $fields ) {
		return empty( $fields ) ? null : sanitize_text_field( $fields );
	 *
	 * @global array $geo_mashup_options
		if ( $enabled ) {
	 *
			$object_id = (int) $_GET['user_id'];
	 *
	 * @return bool|WP_Error
		$user_id = (int) $_POST['user_id'];
	 *
	 *
	 *
	 * @global array $geo_mashup_options
		}
	 *
	 *
	 *
	 * @param id $post_id
	 * @param object $post
	 *
	 *
	 * @param array $shortcode_match
		$tag_index = array_search( 'geo_mashup_save_location',  $shortcode_match );
		}
	 *
	 *

	 *
	 * If an upload is KML, put the URL in an option to be loaded in the response
	 *
	 *
	 *
	 * @global array $geo_mashup_options
		$load_comment_editor = ( !is_admin() && $geo_mashup_options->get( 'overall', 'located_object_name', 'comment' ) == 'true' );
		if ( $user )
		printf( $input_format, 'lat', 'lat', esc_attr( $default_location->lat ) );
		printf( $input_format, 'lng', 'lng', esc_attr( $default_location->lng ) );
			GeoMashup::register_script(
					'geo-mashup-comment-form',
					'js/comment-form.js',
					array( 'jquery' ),
					GEO_MASHUP_VERSION,

		$location = array(
			'lat' => (float) $_POST['comment_location']['lat'],
			'lng' => (float) $_POST['comment_location']['lng']
		);

		GeoMashupDB::set_object_location( 'comment', $comment_id, $location );
		if ( isset( $_REQUEST['callback'] ) ) {
			$json = esc_js( $_REQUEST['callback'] ) . '(' . $json . ')';
		}
		$json = GeoMashup::get_locations_json( GeoMashupDB::sanitize_query_args( $_REQUEST ) );
			$json = esc_js( $_REQUEST['callback'] ) . '(' . $json . ')';