Description: Hardening wp prepare
 Fixes security bug where wpdb->prepare() can create unexpected and
 unsafe queries leading to potential SQL injection (SQLi). WordPress
 core is not directly vulnerable to this issue, but we’ve added
 hardening to prevent plugins and themes from accidentally causing
 a vulnerability. 
 CVE-2017-14723
Author: aaroncampbell@wordpress.org
Origin: upstream, https://core.trac.wordpress.org/changeset/41498/branches/4.7
Bug-Debian: https://bugs.debian.org/876274
Applied-Upstream: 4.8.2
Reviewed-by: Craig Small <csmall@debian.org>
Last-Update: 2017-09-23

--- a/wp-includes/wp-db.php
+++ b/wp-includes/wp-db.php
@@ -1299,13 +1299,23 @@
 
 		$args = func_get_args();
 		array_shift( $args );
+
 		// If args were passed as an array (as in vsprintf), move them up
-		if ( isset( $args[0] ) && is_array($args[0]) )
+		if ( is_array( $args[0] ) && count( $args ) == 1 ) {
 			$args = $args[0];
+		}
+
+		foreach ( $args as $arg ) {
+			if ( ! is_scalar( $arg ) ) {
+				_doing_it_wrong( 'wpdb::prepare', sprintf( 'Unsupported value type (%s).', gettype( $arg ) ), '4.7.6' );
+			}
+		}
+
 		$query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
 		$query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
 		$query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
 		$query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
+		$query = preg_replace( '/%(?:%|$|([^dsF]))/', '%%\\1', $query ); // escape any unescaped percents 
 		array_walk( $args, array( $this, 'escape_by_ref' ) );
 		return @vsprintf( $query, $args );
 	}
@@ -2888,7 +2898,8 @@
 					}
 
 					if ( is_array( $value['length'] ) ) {
-						$queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), %.0f ) USING $connection_charset )", $value['value'], $value['length']['length'] );
+						$length = sprintf( '%.0f', $value['length']['length'] );
+						$queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), $length ) USING $connection_charset )", $value['value'] );
 					} else if ( 'binary' !== $charset ) {
 						// If we don't have a length, there's no need to convert binary - it will always return the same result.
 						$queries[ $col ] = $this->prepare( "CONVERT( CONVERT( %s USING $charset ) USING $connection_charset )", $value['value'] );
