Index: wp-comments-post.php
===================================================================
--- wp-comments-post.php	(revision 15177)
+++ wp-comments-post.php	(working copy)
@@ -55,16 +55,17 @@
 // If the user is logged in
 $user = wp_get_current_user();
 if ( $user->ID ) {
+	check_admin_referer( "submit-comment_$comment_post_ID", '_wp_comment_nonce' );
+
 	if ( empty( $user->display_name ) )
 		$user->display_name=$user->user_login;
 	$comment_author       = $wpdb->escape($user->display_name);
 	$comment_author_email = $wpdb->escape($user->user_email);
 	$comment_author_url   = $wpdb->escape($user->user_url);
+
 	if ( current_user_can('unfiltered_html') ) {
-		if ( wp_create_nonce('unfiltered-html-comment_' . $comment_post_ID) != $_POST['_wp_unfiltered_html_comment'] ) {
-			kses_remove_filters(); // start with a clean slate
-			kses_init_filters(); // set up the filters
-		}
+		kses_remove_filters(); // start with a clean slate
+		kses_init_filters(); // set up the filters
 	}
 } else {
 	if ( get_option('comment_registration') || 'private' == $status )
Index: wp-includes/default-filters.php
===================================================================
--- wp-includes/default-filters.php	(revision 15177)
+++ wp-includes/default-filters.php	(working copy)
@@ -227,8 +227,10 @@
 add_action( 'publish_post',               '_publish_post_hook',       5, 1 );
 add_action( 'save_post',                  '_save_post_hook',          5, 2 );
 add_action( 'transition_post_status',     '_transition_post_status',  5, 3 );
-add_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce'        );
+add_action( 'comment_form',               'wp_comment_form_nonce'          );
 add_action( 'wp_scheduled_delete',        'wp_scheduled_delete'            );
+add_action( 'pre_comment_on_post',        'wp_comment_impersonation'       );
+add_action( 'comment_impersonation',      'wp_comment_impersonation_email' );
 
 // Navigation menu actions
 add_action( 'trash_post',                 '_wp_trash_menu_item'            );
Index: wp-includes/comment.php
===================================================================
--- wp-includes/comment.php	(revision 15177)
+++ wp-includes/comment.php	(working copy)
@@ -1836,6 +1836,62 @@
 		$client->query('weblogUpdates.ping', get_option('blogname'), $home);
 }
 
+
+/**
+ * Hook for preventing comment impersonation of registered user by logged out
+ * user.
+ *
+ * Impersonation of registered user by logged in user handled by
+ * wp-comments-post.php
+ *
+ * CSRF protection for logged in users provided by wp_comment_form_nonce()
+ *
+ * @since 3.1
+ * @uses do_action() Calls 'comment_impersonation' hook.
+ */
+function wp_comment_impersonation() {
+	global $current_user;
+
+	// It's a registered user.  Depend on:
+	//   CSRF prevention in wp_comment_form_nonce()
+	//   form submission overwrite in wp-comments-post.php
+	if ( $current_user->ID )
+		return;
+
+	do_action( 'comment_impersonation' );
+}
+
+/**
+ * Default comment impersonation prevention method.
+ *
+ * Attached to 'comment_impersonation' hook.
+ *
+ * @since 3.1
+ * @uses wp_comment_impersonation_email_check()
+ */
+function wp_comment_impersonation_email() {
+	add_filter( 'pre_comment_author_email', 'wp_comment_impersonation_email_check', 100 );
+}
+
+/**
+ * Checks email submitted by non-logged-in commenter to catch impersonation
+ * attempts.
+ *
+ * Attached to 'pre_comment_author_email' hook by
+ * wp_comment_impersonation_email()
+ *
+ * @since 3.1
+ *
+ * @param string $email Email address to check
+ * @return string unchanged email or wp_die()
+ */
+function wp_comment_impersonation_email_check( $email ) {
+	if ( get_user_by_email( $email ) )
+		wp_die( __( 'Howdy, Mr. Abagnale.' ) );
+
+	return $email;
+}
+
 //
 // Cache
 //
Index: wp-includes/comment-template.php
===================================================================
--- wp-includes/comment-template.php	(revision 15177)
+++ wp-includes/comment-template.php	(working copy)
@@ -770,29 +770,23 @@
 }
 
 /**
- * Displays form token for unfiltered comments.
+ * Displays form token for comments.
  *
- * Will only display nonce token if the current user has permissions for
- * unfiltered html. Won't display the token for other users.
+ * CSRF protection for comments from registered users.  Does not protect against
+ * "manual" impersonation.
  *
- * The function was backported to 2.0.10 and was added to versions 2.1.3 and
- * above. Does not exist in versions prior to 2.0.10 in the 2.0 branch and in
- * the 2.1 branch, prior to 2.1.3. Technically added in 2.2.0.
- *
- * Backported to 2.0.10.
- *
  * @since 2.1.3
+ * @since 2.0.10
  * @uses $post Gets the ID of the current post for the token
  */
-function wp_comment_form_unfiltered_html_nonce() {
+function wp_comment_form_nonce() {
 	global $post;
 
 	$post_id = 0;
 	if ( !empty($post) )
 		$post_id = $post->ID;
 
-	if ( current_user_can('unfiltered_html') )
-		wp_nonce_field('unfiltered-html-comment_' . $post_id, '_wp_unfiltered_html_comment', false);
+	wp_nonce_field( "submit-comment_$post_id", '_wp_comment_nonce', false );
 }
 
 /**
Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 15177)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -721,11 +721,10 @@
 		$comment_author_email = $wpdb->escape($user->user_email);
 		$comment_author_url   = $wpdb->escape($user->user_url);
 		$comment_content      = trim($_POST['content']);
+		
 		if ( current_user_can('unfiltered_html') ) {
-			if ( wp_create_nonce('unfiltered-html-comment_' . $comment_post_ID) != $_POST['_wp_unfiltered_html_comment'] ) {
-				kses_remove_filters(); // start with a clean slate
-				kses_init_filters(); // set up the filters
-			}
+			kses_remove_filters(); // start with a clean slate
+			kses_init_filters(); // set up the filters
 		}
 	} else {
 		die( __('Sorry, you must be logged in to reply to a comment.') );
