diff --git a/core/includes/token.inc b/core/includes/token.inc
index 7a5fea1..16c056e 100644
--- a/core/includes/token.inc
+++ b/core/includes/token.inc
@@ -157,13 +157,18 @@ function token_scan($text) {
  *     encoding or truncation to a specific length.
  *   - sanitize: A boolean flag indicating that tokens should be sanitized for
  *     display to a web browser. Developers who set this option to FALSE assume
- *     responsibility for running filter_xss(), check_plain() or other
- *     appropriate scrubbing functions before displaying data to users.
+ *     responsibility for running filter_xss() or other appropriate scrubbing
+ *     functions before displaying data to users.
  *
  * @return
  *   An associative array of replacement values, keyed by the original 'raw'
  *   tokens that were found in the source text. For example:
  *   $results['[node:title]'] = 'My new node';
+ *   Values are always considered HTML, so all plain-text values have already
+ *   been passed through check_plain(). Depending on $options['sanitize],
+ *   callers may need to sanitize the HTML using filter_xss() etc. If the values
+ *   are to be used in a non-HTML context, e.g. in the subject of an email, they
+ *   should be converted to plain text using decode_entities(strip_tags(...)).
  *
  * @see hook_tokens()
  * @see hook_tokens_alter()
diff --git a/core/modules/comment/comment.test b/core/modules/comment/comment.test
index 2e96ba3..cdf334b 100644
--- a/core/modules/comment/comment.test
+++ b/core/modules/comment/comment.test
@@ -1759,15 +1759,15 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
     $tests = array();
     $tests['[comment:cid]'] = $comment->cid;
     $tests['[comment:hostname]'] = check_plain($comment->hostname);
-    $tests['[comment:name]'] = filter_xss($comment->name);
+    $tests['[comment:name]'] = check_plain($comment->name);
     $tests['[comment:mail]'] = check_plain($this->admin_user->mail);
     $tests['[comment:homepage]'] = check_url($comment->homepage);
-    $tests['[comment:title]'] = filter_xss($comment->subject);
+    $tests['[comment:title]'] = check_plain($comment->subject);
     $tests['[comment:body]'] = _text_sanitize($instance, LANGUAGE_NONE, $comment->comment_body[LANGUAGE_NONE][0], 'value');
-    $tests['[comment:url]'] = url('comment/' . $comment->cid, $url_options + array('fragment' => 'comment-' . $comment->cid));
-    $tests['[comment:edit-url]'] = url('comment/' . $comment->cid . '/edit', $url_options);
-    $tests['[comment:created:since]'] = format_interval(REQUEST_TIME - $comment->created, 2, $language->language);
-    $tests['[comment:changed:since]'] = format_interval(REQUEST_TIME - $comment->changed, 2, $language->language);
+    $tests['[comment:url]'] = check_plain(url('comment/' . $comment->cid, $url_options + array('fragment' => 'comment-' . $comment->cid)));
+    $tests['[comment:edit-url]'] = check_plain(url('comment/' . $comment->cid . '/edit', $url_options));
+    $tests['[comment:created:since]'] = check_plain(format_interval(REQUEST_TIME - $comment->created, 2, $language->language));
+    $tests['[comment:changed:since]'] = check_plain(format_interval(REQUEST_TIME - $comment->changed, 2, $language->language));
     $tests['[comment:parent:cid]'] = $comment->pid;
     $tests['[comment:parent:title]'] = check_plain($parent_comment->subject);
     $tests['[comment:node:nid]'] = $comment->nid;
@@ -1784,15 +1784,8 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[comment:hostname]'] = $comment->hostname;
-    $tests['[comment:name]'] = $comment->name;
-    $tests['[comment:mail]'] = $this->admin_user->mail;
-    $tests['[comment:homepage]'] = $comment->homepage;
-    $tests['[comment:title]'] = $comment->subject;
     $tests['[comment:body]'] = $comment->comment_body[LANGUAGE_NONE][0]['value'];
     $tests['[comment:parent:title]'] = $parent_comment->subject;
-    $tests['[comment:node:title]'] = $node->title;
-    $tests['[comment:author:name]'] = $this->admin_user->name;
 
     foreach ($tests as $input => $expected) {
       $output = token_replace($input, array('comment' => $comment), array('language' => $language, 'sanitize' => FALSE));
diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc
index c495ec3..2f9d1c0 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -127,12 +127,12 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
 
         // Poster identity information for comments
         case 'hostname':
-          $replacements[$original] = $sanitize ? check_plain($comment->hostname) : $comment->hostname;
+          $replacements[$original] = check_plain($comment->hostname);
           break;
 
         case 'name':
           $name = ($comment->uid == 0) ? variable_get('anonymous', t('Anonymous')) : $comment->name;
-          $replacements[$original] = $sanitize ? filter_xss($name) : $name;
+          $replacements[$original] = check_plain($name);
           break;
 
         case 'mail':
@@ -143,15 +143,15 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
           else {
             $mail = $comment->mail;
           }
-          $replacements[$original] = $sanitize ? check_plain($mail) : $mail;
+          $replacements[$original] = check_plain($mail);
           break;
 
         case 'homepage':
-          $replacements[$original] = $sanitize ? check_url($comment->homepage) : $comment->homepage;
+          $replacements[$original] = $sanitize ? check_url($comment->homepage) : check_plain($comment->homepage);
           break;
 
         case 'title':
-          $replacements[$original] = $sanitize ? filter_xss($comment->subject) : $comment->subject;
+          $replacements[$original] = check_plain($comment->subject);
           break;
 
         case 'body':
@@ -165,38 +165,37 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
         // Comment related URLs.
         case 'url':
           $url_options['fragment']  = 'comment-' . $comment->cid;
-          $replacements[$original] = url('comment/' . $comment->cid, $url_options);
+          $replacements[$original] = check_plain(url('comment/' . $comment->cid, $url_options));
           break;
 
         case 'edit-url':
           $url_options['fragment'] = NULL;
-          $replacements[$original] = url('comment/' . $comment->cid . '/edit', $url_options);
+          $replacements[$original] = check_plain(url('comment/' . $comment->cid . '/edit', $url_options));
           break;
 
         // Default values for the chained tokens handled below.
         case 'author':
-          $replacements[$original] = $sanitize ? filter_xss($comment->name) : $comment->name;
+          $replacements[$original] = check_plain($comment->name);
           break;
 
         case 'parent':
           if (!empty($comment->pid)) {
             $parent = comment_load($comment->pid);
-            $replacements[$original] = $sanitize ? filter_xss($parent->subject) : $parent->subject;
+            $replacements[$original] = check_plain($parent->subject);
           }
           break;
 
         case 'created':
-          $replacements[$original] = format_date($comment->created, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($comment->created, 'medium', '', NULL, $language_code));
           break;
 
         case 'changed':
-          $replacements[$original] = format_date($comment->changed, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($comment->changed, 'medium', '', NULL, $language_code));
           break;
 
         case 'node':
           $node = node_load($comment->nid);
-          $title = $node->title;
-          $replacements[$original] = $sanitize ? filter_xss($title) : $title;
+          $replacements[$original] = check_plain($node->title);
           break;
       }
     }
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index 7f5906e..84603b5 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -562,7 +562,7 @@ function file_field_widget_uri($field, $instance, $data = array()) {
   $destination = trim($instance['settings']['file_directory'], '/');
 
   // Replace tokens.
-  $destination = token_replace($destination, $data);
+  $destination = decode_entities(strip_tags(token_replace(check_plain($destination), $data, array('sanitize' => FALSE))));
 
   return $field['settings']['uri_scheme'] . '://' . $destination;
 }
diff --git a/core/modules/node/node.test b/core/modules/node/node.test
index 7c20bf8..cd8c5b9 100644
--- a/core/modules/node/node.test
+++ b/core/modules/node/node.test
@@ -2271,13 +2271,13 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
     $tests['[node:body]'] = _text_sanitize($instance, $node->language, $node->body[$node->language][0], 'value');
     $tests['[node:summary]'] = _text_sanitize($instance, $node->language, $node->body[$node->language][0], 'summary');
     $tests['[node:language]'] = check_plain($node->language);
-    $tests['[node:url]'] = url('node/' . $node->nid, $url_options);
-    $tests['[node:edit-url]'] = url('node/' . $node->nid . '/edit', $url_options);
+    $tests['[node:url]'] = check_plain(url('node/' . $node->nid, $url_options));
+    $tests['[node:edit-url]'] = check_plain(url('node/' . $node->nid . '/edit', $url_options));
     $tests['[node:author]'] = check_plain(format_username($account));
     $tests['[node:author:uid]'] = $node->uid;
     $tests['[node:author:name]'] = check_plain(format_username($account));
-    $tests['[node:created:since]'] = format_interval(REQUEST_TIME - $node->created, 2, $language->language);
-    $tests['[node:changed:since]'] = format_interval(REQUEST_TIME - $node->changed, 2, $language->language);
+    $tests['[node:created:since]'] = check_plain(format_interval(REQUEST_TIME - $node->created, 2, $language->language));
+    $tests['[node:changed:since]'] = check_plain(format_interval(REQUEST_TIME - $node->changed, 2, $language->language));
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.'));
@@ -2288,7 +2288,6 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[node:title]'] = $node->title;
     $tests['[node:body]'] = $node->body[$node->language][0]['value'];
     $tests['[node:summary]'] = $node->body[$node->language][0]['summary'];
     $tests['[node:language]'] = $node->language;
diff --git a/core/modules/node/node.tokens.inc b/core/modules/node/node.tokens.inc
index 491ec81..62cebf2 100644
--- a/core/modules/node/node.tokens.inc
+++ b/core/modules/node/node.tokens.inc
@@ -121,16 +121,16 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr
           break;
 
         case 'type':
-          $replacements[$original] = $sanitize ? check_plain($node->type) : $node->type;
+          $replacements[$original] = check_plain($node->type);
           break;
 
         case 'type-name':
           $type_name = node_type_get_name($node);
-          $replacements[$original] = $sanitize ? check_plain($type_name) : $type_name;
+          $replacements[$original] = check_plain($type_name);
           break;
 
         case 'title':
-          $replacements[$original] = $sanitize ? check_plain($node->title) : $node->title;
+          $replacements[$original] = check_plain($node->title);
           break;
 
         case 'body':
@@ -144,30 +144,30 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr
           break;
 
         case 'language':
-          $replacements[$original] = $sanitize ? check_plain($node->language) : $node->language;
+          $replacements[$original] = check_plain($node->language);
           break;
 
         case 'url':
-          $replacements[$original] = url('node/' . $node->nid, $url_options);
+          $replacements[$original] = check_plain(url('node/' . $node->nid, $url_options));
           break;
 
         case 'edit-url':
-          $replacements[$original] = url('node/' . $node->nid . '/edit', $url_options);
+          $replacements[$original] = check_plain(url('node/' . $node->nid . '/edit', $url_options));
           break;
 
         // Default values for the chained tokens handled below.
         case 'author':
           $account = user_load($node->uid);
           $name = format_username($account);
-          $replacements[$original] = $sanitize ? check_plain($name) : $name;
+          $replacements[$original] = check_plain($name);
           break;
 
         case 'created':
-          $replacements[$original] = format_date($node->created, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($node->created, 'medium', '', NULL, $language_code));
           break;
 
         case 'changed':
-          $replacements[$original] = format_date($node->changed, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($node->changed, 'medium', '', NULL, $language_code));
           break;
       }
     }
diff --git a/core/modules/poll/poll.test b/core/modules/poll/poll.test
index 20a4678..f9c6b6d 100644
--- a/core/modules/poll/poll.test
+++ b/core/modules/poll/poll.test
@@ -661,7 +661,7 @@ class PollTokenReplaceTestCase extends PollTestCase {
     // Generate and test sanitized tokens.
     $tests = array();
     $tests['[node:poll-votes]'] = 4;
-    $tests['[node:poll-winner]'] = filter_xss($poll->choice[1]['chtext']);
+    $tests['[node:poll-winner]'] = check_plain($poll->choice[1]['chtext']);
     $tests['[node:poll-winner-votes]'] = 2;
     $tests['[node:poll-winner-percent]'] = 50;
     $tests['[node:poll-duration]'] = format_interval($poll->runtime, 1, $language->language);
@@ -673,14 +673,6 @@ class PollTokenReplaceTestCase extends PollTestCase {
       $output = token_replace($input, array('node' => $poll), array('language' => $language));
       $this->assertEqual($output, $expected, t('Sanitized poll token %token replaced.', array('%token' => $input)));
     }
-
-    // Generate and test unsanitized tokens.
-    $tests['[node:poll-winner]'] = $poll->choice[1]['chtext'];
-
-    foreach ($tests as $input => $expected) {
-      $output = token_replace($input, array('node' => $poll), array('language' => $language, 'sanitize' => FALSE));
-      $this->assertEqual($output, $expected, t('Unsanitized poll token %token replaced.', array('%token' => $input)));
-    }
   }
 }
 
diff --git a/core/modules/poll/poll.tokens.inc b/core/modules/poll/poll.tokens.inc
index eda628b..90069d6 100644
--- a/core/modules/poll/poll.tokens.inc
+++ b/core/modules/poll/poll.tokens.inc
@@ -70,7 +70,7 @@ function poll_tokens($type, $tokens, array $data = array(), array $options = arr
 
         case 'poll-winner':
           if (isset($winner)) {
-            $replacements[$original] = $sanitize ? filter_xss($winner['chtext']) : $winner['chtext'];
+            $replacements[$original] = check_plain($winner['chtext']);
           }
           else {
             $replacements[$original] = '';
@@ -97,7 +97,7 @@ function poll_tokens($type, $tokens, array $data = array(), array $options = arr
           break;
 
         case 'poll-duration':
-          $replacements[$original] = format_interval($node->runtime, 1, $language_code);
+          $replacements[$original] = check_plain(format_interval($node->runtime, 1, $language_code));
           break;
       }
     }
diff --git a/core/modules/statistics/statistics.tokens.inc b/core/modules/statistics/statistics.tokens.inc
index c2c8fc3..42bc6d8 100644
--- a/core/modules/statistics/statistics.tokens.inc
+++ b/core/modules/statistics/statistics.tokens.inc
@@ -49,7 +49,7 @@ function statistics_tokens($type, $tokens, array $data = array(), array $options
       }
       elseif ($name == 'last-view') {
         $statistics = statistics_get($node->nid);
-        $replacements[$original] = format_date($statistics['timestamp']);
+        $replacements[$original] = check_plain(format_date($statistics['timestamp']));
       }
     }
 
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 51f0ecb..afb39a1 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -3769,21 +3769,31 @@ function hook_tokens($type, $tokens, array $data = array(), array $options = arr
           break;
 
         case 'title':
-          $replacements[$original] = $sanitize ? check_plain($node->title) : $node->title;
+          $replacements[$original] = check_plain($node->title);
+          break;
+
+        case 'body':
+        case 'summary':
+          if (!empty($node->body)) {
+            $item = $node->body[$node->language][0];
+            $column = ($name == 'body') ? 'value' : 'summary';
+            $instance = field_info_instance('node', 'body', $node->type);
+            $replacements[$original] = $sanitize ? _text_sanitize($instance, $node->language, $item, $column) : $item[$column];
+          }
           break;
 
         case 'edit-url':
-          $replacements[$original] = url('node/' . $node->nid . '/edit', $url_options);
+          $replacements[$original] = check_plain(url('node/' . $node->nid . '/edit', $url_options));
           break;
 
         // Default values for the chained tokens handled below.
         case 'author':
           $name = ($node->uid == 0) ? variable_get('anonymous', t('Anonymous')) : $node->name;
-          $replacements[$original] = $sanitize ? filter_xss($name) : $name;
+          $replacements[$original] = check_plain($name);
           break;
 
         case 'created':
-          $replacements[$original] = format_date($node->created, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($node->created, 'medium', '', NULL, $language_code));
           break;
       }
     }
@@ -3827,7 +3837,6 @@ function hook_tokens_alter(array &$replacements, array $context) {
   else {
     $language_code = NULL;
   }
-  $sanitize = !empty($options['sanitize']);
 
   if ($context['type'] == 'node' && !empty($context['data']['node'])) {
     $node = $context['data']['node'];
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f16b73f..7d00852 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3186,7 +3186,7 @@ function system_send_email_action($entity, $context) {
     $context['node'] = $entity;
   }
 
-  $recipient = token_replace($context['recipient'], $context);
+  $recipient = decode_entities(strip_tags(token_replace(check_plain($context['recipient']), $context, array('sanitize' => FALSE))));
 
   // If the recipient is a registered user with a language preference, use
   // the recipient's preferred language. Otherwise, use the system default
@@ -3214,7 +3214,7 @@ function system_send_email_action($entity, $context) {
 function system_mail($key, &$message, $params) {
   $context = $params['context'];
 
-  $subject = token_replace($context['subject'], $context);
+  $subject = decode_entities(strip_tags(token_replace(check_plain($context['subject']), $context, array('sanitize' => FALSE))));
   $body = token_replace($context['message'], $context);
 
   $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
@@ -3295,7 +3295,7 @@ function system_goto_action_submit($form, $form_state) {
  * @ingroup actions
  */
 function system_goto_action($entity, $context) {
-  drupal_goto(token_replace($context['url'], $context));
+  drupal_goto(decode_entities(strip_tags(token_replace(check_plain($context['url']), $context, array('sanitize' => FALSE)))));
 }
 
 /**
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 4e3761d..1a3d689 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -1827,8 +1827,9 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
   function testTokenReplacement() {
     // Create the initial objects.
     $account = $this->drupalCreateUser();
-    $node = $this->drupalCreateNode(array('uid' => $account->uid));
+    $node = $this->drupalCreateNode(array('uid' => $account->uid, 'type' => 'page'));
     $node->title = '<blink>Blinking Text</blink>';
+    $node->body[LANGUAGE_NONE][0]['value'] = 'Invalid HTML: & <>';
     global $user, $language;
 
     $source  = '[node:title]';         // Title of the node we passed in
@@ -1841,9 +1842,9 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
 
     $target  = check_plain($node->title);
     $target .= check_plain($account->name);
-    $target .= format_interval(REQUEST_TIME - $node->created, 2, $language->language);
+    $target .= check_plain(format_interval(REQUEST_TIME - $node->created, 2, $language->language));
     $target .= check_plain($user->name);
-    $target .= format_date(REQUEST_TIME, 'short', '', NULL, $language->language);
+    $target .= check_plain(format_date(REQUEST_TIME, 'short', '', NULL, $language->language));
 
     // Test that the clear parameter cleans out non-existent tokens.
     $result = token_replace($source, array('node' => $node), array('language' => $language, 'clear' => TRUE));
@@ -1858,13 +1859,18 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
     // Check that the results of token_generate are sanitized properly. This does NOT
     // test the cleanliness of every token -- just that the $sanitize flag is being
     // passed properly through the call stack and being handled correctly by a 'known'
-    // token, [node:title].
-    $raw_tokens = array('title' => '[node:title]');
+    // token, [node:body].
+    $raw_tokens = array('title' => '[node:title]', 'body' => '[node:body]');
     $generated = token_generate('node', $raw_tokens, array('node' => $node));
+    $instance = field_info_instance('node', 'body', 'page');
+
     $this->assertEqual($generated['[node:title]'], check_plain($node->title), t('Token sanitized.'));
+    $this->assertEqual($generated['[node:body]'], _text_sanitize($instance, $node->language, $node->body[LANGUAGE_NONE][0], 'value'), t('Token sanitized.'));
+    $this->assertNotEqual($generated['[node:body]'], $node->body[LANGUAGE_NONE][0]['value'], t('Token sanitized.'));
 
     $generated = token_generate('node', $raw_tokens, array('node' => $node), array('sanitize' => FALSE));
-    $this->assertEqual($generated['[node:title]'], $node->title, t('Unsanitized token generated properly.'));
+    $this->assertEqual($generated['[node:title]'], check_plain($node->title), t('Unsanitized token generated properly.'));
+    $this->assertEqual($generated['[node:body]'], $node->body[LANGUAGE_NONE][0]['value'], t('Unsanitized token generated properly.'));
   }
 
   /**
@@ -1913,11 +1919,11 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
     // Generate and test sanitized tokens.
     $tests = array();
     $tests['[site:name]'] = check_plain(variable_get('site_name', 'Drupal'));
-    $tests['[site:slogan]'] = check_plain(variable_get('site_slogan', ''));
+    $tests['[site:slogan]'] = filter_xss_admin(variable_get('site_slogan', ''));
     $tests['[site:mail]'] = 'simpletest@example.com';
-    $tests['[site:url]'] = url('<front>', $url_options);
-    $tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options));
-    $tests['[site:login-url]'] = url('user', $url_options);
+    $tests['[site:url]'] = check_plain(url('<front>', $url_options));
+    $tests['[site:url-brief]'] = check_plain(preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options)));
+    $tests['[site:login-url]'] = check_plain(url('user', $url_options));
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.'));
@@ -1928,7 +1934,7 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[site:name]'] = variable_get('site_name', 'Drupal');
+    $tests['[site:name]'] = check_plain(variable_get('site_name', 'Drupal'));
     $tests['[site:slogan]'] = variable_get('site_slogan', '');
 
     foreach ($tests as $input => $expected) {
@@ -1948,12 +1954,12 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
 
     // Generate and test tokens.
     $tests = array();
-    $tests['[date:short]'] = format_date($date, 'short', '', NULL, $language->language);
-    $tests['[date:medium]'] = format_date($date, 'medium', '', NULL, $language->language);
-    $tests['[date:long]'] = format_date($date, 'long', '', NULL, $language->language);
-    $tests['[date:custom:m/j/Y]'] = format_date($date, 'custom', 'm/j/Y', NULL, $language->language);
-    $tests['[date:since]'] = format_interval((REQUEST_TIME - $date), 2, $language->language);
-    $tests['[date:raw]'] = filter_xss($date);
+    $tests['[date:short]'] = check_plain(format_date($date, 'short', '', NULL, $language->language));
+    $tests['[date:medium]'] = check_plain(format_date($date, 'medium', '', NULL, $language->language));
+    $tests['[date:long]'] = check_plain(format_date($date, 'long', '', NULL, $language->language));
+    $tests['[date:custom:m/j/Y]'] = check_plain(format_date($date, 'custom', 'm/j/Y', NULL, $language->language));
+    $tests['[date:since]'] = check_plain(format_interval((REQUEST_TIME - $date), 2, $language->language));
+    $tests['[date:raw]'] = check_plain($date);
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.'));
diff --git a/core/modules/system/system.tokens.inc b/core/modules/system/system.tokens.inc
index b612d10..977f915 100644
--- a/core/modules/system/system.tokens.inc
+++ b/core/modules/system/system.tokens.inc
@@ -146,28 +146,28 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
       switch ($name) {
         case 'name':
           $site_name = variable_get('site_name', 'Drupal');
-          $replacements[$original] = $sanitize ? check_plain($site_name) : $site_name;
+          $replacements[$original] = check_plain($site_name);
           break;
 
         case 'slogan':
           $slogan = variable_get('site_slogan', '');
-          $replacements[$original] = $sanitize ? check_plain($slogan) : $slogan;
+          $replacements[$original] = $sanitize ? filter_xss_admin($slogan) : $slogan;
           break;
 
         case 'mail':
-          $replacements[$original] = variable_get('site_mail', '');
+          $replacements[$original] = check_plain(variable_get('site_mail', ''));
           break;
 
         case 'url':
-          $replacements[$original] = url('<front>', $url_options);
+          $replacements[$original] = check_plain(url('<front>', $url_options));
           break;
 
         case 'url-brief':
-          $replacements[$original] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options));
+          $replacements[$original] = check_plain(preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options)));
           break;
 
         case 'login-url':
-          $replacements[$original] = url('user', $url_options);
+          $replacements[$original] = check_plain(url('user', $url_options));
           break;
       }
     }
@@ -184,30 +184,30 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
     foreach ($tokens as $name => $original) {
       switch ($name) {
         case 'short':
-          $replacements[$original] = format_date($date, 'short', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($date, 'short', '', NULL, $language_code));
           break;
 
         case 'medium':
-          $replacements[$original] = format_date($date, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($date, 'medium', '', NULL, $language_code));
           break;
 
         case 'long':
-          $replacements[$original] = format_date($date, 'long', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($date, 'long', '', NULL, $language_code));
           break;
 
         case 'since':
-          $replacements[$original] = format_interval((REQUEST_TIME - $date), 2, $language_code);
+          $replacements[$original] = check_plain(format_interval((REQUEST_TIME - $date), 2, $language_code));
           break;
 
         case 'raw':
-          $replacements[$original] = $sanitize ? check_plain($date) : $date;
+          $replacements[$original] = check_plain($date);
           break;
       }
     }
 
     if ($created_tokens = token_find_with_prefix($tokens, 'custom')) {
       foreach ($created_tokens as $name => $original) {
-        $replacements[$original] = format_date($date, 'custom', $name, NULL, $language_code);
+        $replacements[$original] = check_plain(format_date($date, 'custom', $name, NULL, $language_code));
       }
     }
   }
@@ -224,15 +224,15 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
 
         // Essential file data
         case 'name':
-          $replacements[$original] = $sanitize ? check_plain($file->filename) : $file->filename;
+          $replacements[$original] = check_plain($file->filename);
           break;
 
         case 'path':
-          $replacements[$original] = $sanitize ? check_plain($file->uri) : $file->uri;
+          $replacements[$original] = check_plain($file->uri);
           break;
 
         case 'mime':
-          $replacements[$original] = $sanitize ? check_plain($file->filemime) : $file->filemime;
+          $replacements[$original] = check_plain($file->filemime);
           break;
 
         case 'size':
@@ -240,18 +240,18 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
           break;
 
         case 'url':
-          $replacements[$original] = $sanitize ? check_plain(file_create_url($file->uri)) : file_create_url($file->uri);
+          $replacements[$original] = check_plain(file_create_url($file->uri));
           break;
 
         // These tokens are default variations on the chained tokens handled below.
         case 'timestamp':
-          $replacements[$original] = format_date($file->timestamp, 'medium', '', NULL, $language_code);
+          $replacements[$original] = check_plain(format_date($file->timestamp, 'medium', '', NULL, $language_code));
           break;
 
         case 'owner':
           $account = user_load($file->uid);
           $name = format_username($account);
-          $replacements[$original] = $sanitize ? check_plain($name) : $name;
+          $replacements[$original] = check_plain($name);
           break;
       }
     }
diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test
index dcb8a17..5539519 100644
--- a/core/modules/taxonomy/taxonomy.test
+++ b/core/modules/taxonomy/taxonomy.test
@@ -1220,7 +1220,7 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
     $tests['[term:tid]'] = $term2->tid;
     $tests['[term:name]'] = check_plain($term2->name);
     $tests['[term:description]'] = check_markup($term2->description, $term2->format);
-    $tests['[term:url]'] = url('taxonomy/term/' . $term2->tid, array('absolute' => TRUE));
+    $tests['[term:url]'] = check_plain(url('taxonomy/term/' . $term2->tid, array('absolute' => TRUE)));
     $tests['[term:node-count]'] = 1;
     $tests['[term:parent:name]'] = check_plain($term1->name);
     $tests['[term:parent:url]'] = url('taxonomy/term/' . $term1->tid, array('absolute' => TRUE));
@@ -1235,17 +1235,6 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
       $this->assertEqual($output, $expected, t('Sanitized taxonomy term token %token replaced.', array('%token' => $input)));
     }
 
-    // Generate and test unsanitized tokens.
-    $tests['[term:name]'] = $term2->name;
-    $tests['[term:description]'] = $term2->description;
-    $tests['[term:parent:name]'] = $term1->name;
-    $tests['[term:vocabulary:name]'] = $this->vocabulary->name;
-
-    foreach ($tests as $input => $expected) {
-      $output = token_replace($input, array('term' => $term2), array('language' => $language, 'sanitize' => FALSE));
-      $this->assertEqual($output, $expected, t('Unsanitized taxonomy term token %token replaced.', array('%token' => $input)));
-    }
-
     // Generate and test sanitized tokens.
     $tests = array();
     $tests['[vocabulary:vid]'] = $this->vocabulary->vid;
@@ -1263,7 +1252,6 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[vocabulary:name]'] = $this->vocabulary->name;
     $tests['[vocabulary:description]'] = $this->vocabulary->description;
 
     foreach ($tests as $input => $expected) {
diff --git a/core/modules/taxonomy/taxonomy.tokens.inc b/core/modules/taxonomy/taxonomy.tokens.inc
index f8ae457..ab95a8c 100644
--- a/core/modules/taxonomy/taxonomy.tokens.inc
+++ b/core/modules/taxonomy/taxonomy.tokens.inc
@@ -102,16 +102,16 @@ function taxonomy_tokens($type, $tokens, array $data = array(), array $options =
           break;
 
         case 'name':
-          $replacements[$original] = $sanitize ? check_plain($term->name) : $term->name;
+          $replacements[$original] = check_plain($term->name);
           break;
 
         case 'description':
-          $replacements[$original] = $sanitize ? check_markup($term->description, $term->format, '', TRUE) : $term->description;
+          $replacements[$original] = check_markup($term->description, $term->format, '', TRUE);
           break;
 
         case 'url':
           $uri = entity_uri('taxonomy_term', $term);
-          $replacements[$original] = url($uri['path'], array_merge($uri['options'], array('absolute' => TRUE)));
+          $replacements[$original] = check_plain(url($uri['path'], array_merge($uri['options'], array('absolute' => TRUE))));
           break;
 
         case 'node-count':
@@ -157,7 +157,7 @@ function taxonomy_tokens($type, $tokens, array $data = array(), array $options =
           break;
 
         case 'name':
-          $replacements[$original] = $sanitize ? check_plain($vocabulary->name) : $vocabulary->name;
+          $replacements[$original] = check_plain($vocabulary->name);
           break;
 
         case 'description':
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 6f1bc3c..4e66355 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -2566,7 +2566,7 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
 function user_mail($key, &$message, $params) {
   $language = $message['language'];
   $variables = array('user' => $params['account']);
-  $message['subject'] .= _user_mail_text($key . '_subject', $language, $variables);
+  $message['subject'] .= decode_entities(strip_tags(_user_mail_text($key . '_subject', $language, $variables)));
   $message['body'][] = _user_mail_text($key . '_body', $language, $variables);
 }
 
diff --git a/core/modules/user/user.test b/core/modules/user/user.test
index 66c4903..de6742e 100644
--- a/core/modules/user/user.test
+++ b/core/modules/user/user.test
@@ -1931,16 +1931,6 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
       $output = token_replace($input, array('user' => $account), array('language' => $language));
       $this->assertEqual($output, $expected, t('Sanitized user token %token replaced.', array('%token' => $input)));
     }
-
-    // Generate and test unsanitized tokens.
-    $tests['[user:name]'] = format_username($account);
-    $tests['[user:mail]'] = $account->mail;
-    $tests['[current-user:name]'] = format_username($global_account);
-
-    foreach ($tests as $input => $expected) {
-      $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
-      $this->assertEqual($output, $expected, t('Unsanitized user token %token replaced.', array('%token' => $input)));
-    }
   }
 }
 
diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc
index 8dcea4b..343ecd3 100644
--- a/core/modules/user/user.tokens.inc
+++ b/core/modules/user/user.tokens.inc
@@ -70,7 +70,6 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
   else {
     $language_code = NULL;
   }
-  $sanitize = !empty($options['sanitize']);
 
   $replacements = array();
 
@@ -86,29 +85,29 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
 
         case 'name':
           $name = format_username($account);
-          $replacements[$original] = $sanitize ? check_plain($name) : $name;
+          $replacements[$original] = check_plain($name);
           break;
 
         case 'mail':
-          $replacements[$original] = $sanitize ? check_plain($account->mail) : $account->mail;
+          $replacements[$original] = check_plain($account->mail);
           break;
 
         case 'url':
-          $replacements[$original] = !empty($account->uid) ? url("user/$account->uid", $url_options) : t('not yet assigned');
+          $replacements[$original] = !empty($account->uid) ? check_plain(url("user/$account->uid", $url_options)) : t('not yet assigned');
           break;
 
         case 'edit-url':
-          $replacements[$original] = !empty($account->uid) ? url("user/$account->uid/edit", $url_options) : t('not yet assigned');
+          $replacements[$original] = !empty($account->uid) ? check_plain(url("user/$account->uid/edit", $url_options)) : t('not yet assigned');
           break;
 
         // These tokens are default variations on the chained tokens handled below.
         case 'last-login':
-          $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $language_code) : t('never');
+          $replacements[$original] = !empty($account->login) ? check_plain(format_date($account->login, 'medium', '', NULL, $language_code)) : t('never');
           break;
 
         case 'created':
           // In the case of user_presave the created date may not yet be set.
-          $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created');
+          $replacements[$original] = !empty($account->created) ? check_plain(format_date($account->created, 'medium', '', NULL, $language_code)) : t('not yet created');
           break;
       }
     }
