Index: src/wp-admin/admin-ajax.php
===================================================================
--- src/wp-admin/admin-ajax.php	(revision 27810)
+++ src/wp-admin/admin-ajax.php	(working copy)
@@ -58,7 +58,7 @@
 	'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
 	'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
 	'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
-	'save-user-color-scheme', 'update-widget',
+	'save-user-color-scheme', 'update-widget', 'query-themes'
 );
 
 // Register core Ajax calls.
Index: src/wp-admin/includes/ajax-actions.php
===================================================================
--- src/wp-admin/includes/ajax-actions.php	(revision 27810)
+++ src/wp-admin/includes/ajax-actions.php	(working copy)
@@ -2207,3 +2207,40 @@
 	update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
 	wp_send_json_success();
 }
+
+/**
+ * Perform a query_themes lookup on api.wordpress.org.
+ *
+ * @since x.x.x
+ */
+function wp_ajax_query_themes() {
+	$url = 'http://api.wordpress.org/themes/info/1.1/?action=query_themes';
+
+	check_ajax_referer( 'query-themes', 'nonce' );
+
+	$request = wp_remote_post( $url, array(
+		'body' => wp_unslash( $_POST['api'] ),
+	) );
+
+	if ( is_wp_error( $request ) ) {
+		wp_send_json_error();
+	}
+	if ( 200 != wp_remote_retrieve_response_code( $request ) ) {
+		wp_send_json_error();
+	}
+
+	$json = json_decode( wp_remote_retrieve_body( $request ) );
+
+	if ( !$json ) {
+		wp_send_json_error();
+	}
+
+	if ( isset( $json->themes ) ) {
+		foreach ( $json->themes as & $theme ) {
+			$theme->num_ratings_text = sprintf( _n( 'Based on %s rating.', 'Based on %s ratings.', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
+		}
+	}
+
+	wp_send_json_success( $json );
+
+}
\ No newline at end of file
Index: src/wp-admin/js/theme.js
===================================================================
--- src/wp-admin/js/theme.js	(revision 27913)
+++ src/wp-admin/js/theme.js	(working copy)
@@ -245,7 +245,13 @@
 
 		// Otherwise, send a new API call and add it to the cache.
 		if ( ! query ) {
-			query = this.apiCall( request ).done( function( data ) {
+			query = this.apiCall( request ).done( function( response ) {
+				if ( !response.success ) {
+					self.trigger( 'query:fail' );
+					return;
+				}
+				data = response.data;
+
 				// Update the collection with the queried data.
 				self.reset( data.themes );
 				count = data.info.results;
@@ -267,7 +273,13 @@
 		} else {
 			// If it's a paginated request we need to fetch more themes...
 			if ( isPaginated ) {
-				return this.apiCall( request, isPaginated ).done( function( data ) {
+				return this.apiCall( request, isPaginated ).done( function( response ) {
+					if ( !response.success ) {
+						self.trigger( 'query:fail' );
+						return;
+					}
+					data = response.data;
+
 					// Add the new themes to the current collection
 					// @todo update counter
 					self.add( data.themes );
@@ -311,30 +323,33 @@
 
 		// Ajax request to .org API
 		return $.ajax({
-			url: 'https://api.wordpress.org/themes/info/1.1/?action=query_themes',
+			url: ajaxurl,
 
 			// We want JSON data
 			dataType: 'json',
 			type: 'POST',
-			crossDomain: true,
 
 			// Request data
 			data: {
-				action: 'query_themes',
-				request: _.extend({
-					per_page: 72,
-					fields: {
-						description: true,
-						tested: true,
-						requires: true,
-						rating: true,
-						downloaded: true,
-						downloadLink: true,
-						last_updated: true,
-						homepage: true,
-						num_ratings: true
-					}
-				}, request)
+				action: 'query-themes',
+				nonce: themes.data.settings._nonceQuery,
+				api: {
+					action: 'query_themes',
+					request: _.extend({
+						per_page: 72,
+						fields: {
+							description: true,
+							tested: true,
+							requires: true,
+							rating: true,
+							downloaded: true,
+							downloadLink: true,
+							last_updated: true,
+							homepage: true,
+							num_ratings: true
+						}
+					}, request)
+				}
 			},
 
 			beforeSend: function() {
Index: src/wp-admin/theme-install.php
===================================================================
--- src/wp-admin/theme-install.php	(revision 27810)
+++ src/wp-admin/theme-install.php	(working copy)
@@ -41,7 +41,8 @@
 		'installURI'    => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
 		'adminUrl'      => parse_url( self_admin_url(), PHP_URL_PATH ),
 		'updateURI'     => self_admin_url( 'update.php' ),
-		'_nonceInstall' => wp_create_nonce( 'install-theme' )
+		'_nonceInstall' => wp_create_nonce( 'install-theme' ),
+		'_nonceQuery'   => wp_create_nonce( 'query-themes' ),
 	),
 	'l10n' => array(
 		'addNew' => __( 'Add New Theme' ),
@@ -205,7 +206,7 @@
 						<span class="three"></span>
 						<span class="four"></span>
 						<span class="five"></span>
-						<p class="votes"><?php printf( __( 'Based on %s ratings.' ), '{{ data.num_ratings }}' ); ?></p>
+						<p class="votes">{{ data.num_ratings_text }}</p>
 					</div>
 					<div class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></div>
 					<div class="theme-description">{{ data.description }}</div>
