diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 7ab2059..9d482cc 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -387,7 +387,7 @@ function ajax_pre_render_element($element) {
       // uniquely, in which case a match on value is also needed.
       // @see _form_button_was_clicked()
       if (!empty($element['#is_button']) && empty($element['#has_garbage_value'])) {
-        $settings['submit']['_triggering_element_value'] = $element['#value'];
+        $settings['submit']['_triggering_element_value'] = (string) $element['#value'];
       }
     }
 
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 50dc8f3..c89df4e 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -16,6 +16,7 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Utility\Title;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\ClassLoader\ApcClassLoader;
@@ -1180,6 +1181,9 @@ function watchdog($type, $message, array $variables = array(), $severity = WATCH
  */
 function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) {
   if ($message) {
+    if ($message instanceof SafeMarkup) {
+      $message = chr(0) . $message;
+    }
     if (!isset($_SESSION['messages'][$type])) {
       $_SESSION['messages'][$type] = array();
     }
@@ -1223,6 +1227,13 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
  */
 function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
   if ($messages = drupal_set_message()) {
+    foreach ($messages as $type => $messages_typed) {
+      foreach ($messages_typed as $key => $message) {
+        if (!$message instanceof SafeMarkup && $message[0] == chr(0)) {
+          $messages[$type][$key] = new SafeMarkup(substr($message, 1));
+        }
+      }
+    }
     if ($type) {
       if ($clear_queue) {
         unset($_SESSION['messages'][$type]);
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 65aef09..b115700 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -29,6 +29,7 @@
 use Drupal\Core\EventSubscriber\HtmlViewSubscriber;
 use Drupal\Core\Routing\GeneratorNotInitializedException;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AnonymousUserSession;
 
@@ -910,8 +911,7 @@ function l($text, $path, array $options = array()) {
 
   // Sanitize the link text if necessary.
   $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
-
-  return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
+  return new SafeMarkup('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>');
 }
 
 /**
@@ -1464,6 +1464,9 @@ function drupal_html_class($class) {
   // static instead of drupal_static().
   static $classes = array();
 
+  // @todo Needs safe makrup preservation or should be cast to string before
+  // arg is passed to this function?
+  $class = (string) $class;
   if (!isset($classes[$class])) {
     $classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
   }
@@ -2853,6 +2856,7 @@ function drupal_pre_render_conditional_comments($elements) {
  *     - meta: To provide meta information, such as a page refresh.
  *     - link: To refer to stylesheets and other contextual information.
  *     - script: To load JavaScript.
+ *     This is not HTML escaped, do not pass in user input.
  *   - #attributes: (optional) An array of HTML attributes to apply to the
  *     tag.
  *   - #value: (optional) A string containing tag content, such as inline
@@ -2865,7 +2869,9 @@ function drupal_pre_render_conditional_comments($elements) {
 function drupal_pre_render_html_tag($element) {
   $attributes = isset($element['#attributes']) ? new Attribute($element['#attributes']) : '';
   if (!isset($element['#value'])) {
-    $markup = '<' . $element['#tag'] . $attributes . " />\n";
+    // Attributes are safe and we are assuming people don't use this function
+    // and second they don't pass unsafe variables to #tag.
+    $markup = new SafeMarkup('<' . $element['#tag'] . $attributes . " />\n");
   }
   else {
     $markup = '<' . $element['#tag'] . $attributes . '>';
@@ -2877,6 +2883,8 @@ function drupal_pre_render_html_tag($element) {
       $markup .= $element['#value_suffix'];
     }
     $markup .= '</' . $element['#tag'] . ">\n";
+    // @TODO Creating safe markup, avoid if possible!
+    $markup = new SafeMarkup($markup);
   }
   if (!empty($element['#noscript'])) {
     $element['#markup'] = '<noscript>' . $markup . '</noscript>';
@@ -3285,7 +3293,7 @@ function drupal_render_page($page) {
  * @param bool $is_recursive_call
  *   Whether this is a recursive call or not, for internal use.
  *
- * @return string
+ * @return \Drupal\Core\Template\SafeMarkup
  *   The rendered HTML.
  *
  * @see element_info()
@@ -3310,6 +3318,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $cached_element = drupal_render_cache_get($elements);
     if ($cached_element !== FALSE) {
       $elements = $cached_element;
+      $elements['#markup'] = new SafeMarkup($elements['#markup']);
       // Only when we're not in a recursive drupal_render() call,
       // #post_render_cache callbacks must be executed, to prevent breaking the
       // render cache in case of nested elements with #cache set.
@@ -3360,6 +3369,33 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $elements['#children'] = '';
   }
 
+  // Assume still safe unless the element or it's __toString return value aren't
+  // instances of Twig_Markup.
+  $get_string = function ($element)  {
+    if (is_object($element) && method_exists($element, '__toString')) {
+      $markup = $element->__toString();
+    }
+    else {
+      $markup = $element;
+    }
+    // This is necessary because $element can be a RenderWrapper.
+    if ($markup && !$element instanceof SafeMarkup && !$markup instanceof SafeMarkup) {
+      $markup = String::checkPlain($markup);
+    }
+    return $markup;
+  };
+
+  // @TODO: remove wrapping of #markup.
+  if (isset($elements['#markup'])) {
+    if (is_object($elements['#markup']) && method_exists($elements['#markup'], '__toString')) {
+      $markup = $elements['#markup']->__toString();
+    }
+    else {
+      $markup = $elements['#markup'];
+    }
+    $elements['#markup'] = new SafeMarkup($markup);
+  }
+
   // Assume that if #theme is set it represents an implemented hook.
   $theme_is_implemented = isset($elements['#theme']);
 
@@ -3381,8 +3417,9 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   // process as drupal_render_children() but is inlined for speed.
   if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) {
     foreach ($children as $key) {
-      $elements['#children'] .= drupal_render($elements[$key], TRUE);
+      $elements['#children'] .= $get_string(drupal_render($elements[$key], TRUE));
     }
+    $elements['#children'] = new SafeMarkup($elements['#children']);
   }
 
   // If #theme is not implemented and the element has raw #markup as a
@@ -3393,7 +3430,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   // required. Eventually #theme_wrappers will expect both #markup and
   // #children to be a single string as #children.
   if (!$theme_is_implemented && isset($elements['#markup'])) {
-    $elements['#children'] = $elements['#markup'] . $elements['#children'];
+    $elements['#children'] = new SafeMarkup($get_string($elements['#markup']) . $get_string($elements['#children']));
   }
 
   // Let the theme functions in #theme_wrappers add markup around the rendered
@@ -3477,6 +3514,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   }
 
   $elements['#printed'] = TRUE;
+  $elements['#markup'] = new SafeMarkup($elements['#markup']);
   return $elements['#markup'];
 }
 
@@ -3490,7 +3528,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
  *   can be passed in to save another run of
  *   \Drupal\Core\Render\Element::children().
  *
- * @return string
+ * @return \Drupal\Core\Template\SafeMarkup
  *   The rendered HTML of all children of the element.
 
  * @see drupal_render()
@@ -3499,13 +3537,13 @@ function drupal_render_children(&$element, $children_keys = NULL) {
   if ($children_keys === NULL) {
     $children_keys = Element::children($element);
   }
-  $output = '';
+  $markups = array();
   foreach ($children_keys as $key) {
     if (!empty($element[$key])) {
-      $output .= drupal_render($element[$key]);
+      $markups[] = drupal_render($element[$key]);
     }
   }
-  return $output;
+  return SafeMarkup::implode('', $markups);
 }
 
 /**
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 42206a4..9464fe9 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -15,6 +15,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Utility\Color;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -983,7 +984,7 @@ function form_select_options($element, $choices = NULL) {
       $options .= form_select_options($element, $choice);
       $options .= '</optgroup>';
     }
-    elseif (is_object($choice)) {
+    elseif (is_object($choice) && isset($choice->option)) {
       $options .= form_select_options($element, $choice->option);
     }
     else {
@@ -998,7 +999,7 @@ function form_select_options($element, $choices = NULL) {
       $options .= '<option value="' . String::checkPlain($key) . '"' . $selected . '>' . String::checkPlain($choice) . '</option>';
     }
   }
-  return $options;
+  return new SafeMarkup($options);
 }
 
 /**
@@ -1659,7 +1660,7 @@ function theme_tableselect($variables) {
       foreach ($element['#header'] as $fieldname => $title) {
         // A row cell can span over multiple headers, which means less row cells
         // than headers could be present.
-        if (isset($element['#options'][$key][$fieldname])) {
+        if (isset($element['#options'][$key][$fieldname]) && is_array($element['#options'][$key][$fieldname])) {
           // A header can span over multiple cells and in this case the cells
           // are passed in an array. The order of this array determines the
           // order in which they are added.
@@ -1976,7 +1977,7 @@ function form_process_machine_name($element, &$form_state) {
   $element['#machine_name'] += array(
     'source' => array('label'),
     'target' => '#' . $element['#id'],
-    'label' => t('Machine name'),
+    'label' => (string) t('Machine name'),
     'replace_pattern' => '[^a-z0-9_]+',
     'replace' => '_',
     'standalone' => FALSE,
@@ -2009,13 +2010,13 @@ function form_process_machine_name($element, &$form_state) {
   $element['#machine_name']['suffix'] = '#' . $suffix_id;
 
   if ($element['#machine_name']['standalone']) {
-    $element['#suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+    $element['#suffix'] = SafeMarkup::concat($element['#suffix'], new SafeMarkup(' <small id="' . $suffix_id . '">&nbsp;</small>'));
   }
   else {
     // Append a field suffix to the source form element, which will contain
     // the live preview of the machine name.
     $source += array('#field_suffix' => '');
-    $source['#field_suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+    $source['#field_suffix'] = SafeMarkup::concat($source['#field_suffix'], new SafeMarkup(' <small id="' . $suffix_id . '">&nbsp;</small>'));
 
     $parents = array_merge($element['#machine_name']['source'], array('#field_suffix'));
     NestedArray::setValue($form_state['complete_form'], $parents, $source['#field_suffix']);
@@ -2348,6 +2349,9 @@ function template_preprocess_input(&$variables) {
 function theme_input($variables) {
   $element = $variables['element'];
   $attributes = $variables['attributes'];
+  if (!$attributes instanceof Attribute) {
+    throw new \LogicException('Attributes are expected to be an instance of attributes');
+  }
   return '<input' . $attributes . ' />' . drupal_render_children($element);
 }
 
@@ -2976,8 +2980,6 @@ function theme_form_element_label($variables) {
     return '';
   }
 
-  $title = Xss::filterAdmin($element['#title']);
-
   $attributes = array();
   // Style the label as class option to display inline with the element.
   if ($element['#title_display'] == 'after') {
@@ -3008,6 +3010,8 @@ function theme_form_element_label($variables) {
     $attributes['class'][] = 'form-required';
   }
 
+  $title = Xss::filterAdmin($element['#title']);
+
   return '<label' . new Attribute($attributes) . '>' . $title . '</label>';
 }
 
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index e44f13d..7418200 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\Page\MetaElement;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Template\RenderWrapper;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Theme\ThemeSettings;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Render\Element;
@@ -579,7 +580,7 @@ function _theme($hook, $variables = array()) {
   $output = '';
   if (isset($info['function'])) {
     if (function_exists($info['function'])) {
-      $output = $info['function']($variables);
+      $output = new SafeMarkup($info['function']($variables));
     }
   }
   else {
@@ -650,7 +651,7 @@ function _theme($hook, $variables = array()) {
 
   // restore path_to_theme()
   $theme_path = $temp;
-  return (string) $output;
+  return $output;
 }
 
 /**
@@ -2052,7 +2053,10 @@ function template_preprocess_html(&$variables) {
 
   // Wrap function calls in an object so they can be called when printed.
   $variables['head'] = new RenderWrapper(function() use ($page) {
-    return implode("\n", $page->getMetaElements()) . implode("\n", $page->getLinkElements());
+    // HeadElement itself is safe and MetaElement and LinkElement both extend
+    // it so each element are safe. The result of concatenating a lot of them
+    // together is also safe.
+    return new SafeMarkup(implode("\n", $page->getMetaElements()) . implode("\n", $page->getLinkElements()));
   });
   $variables['styles'] = new RenderWrapper('drupal_get_css');
   $variables['scripts'] = new RenderWrapper('drupal_get_js');
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index 8a19a49..09957df 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Sets up the theming system for maintenance page.
@@ -110,6 +111,8 @@ function _drupal_maintenance_theme() {
  * @param $variables
  *   An associative array containing:
  *   - items: An associative array of maintenance tasks.
+ *     It's the caller's responsibility to ensure this array's items contains no
+ *     XSS holes.
  *   - active: The key for the currently active maintenance task.
  *
  * @ingroup themeable
@@ -178,6 +181,7 @@ function theme_authorize_report($variables) {
     }
     $output .= '</div>';
   }
+
   return $output;
 }
 
@@ -187,6 +191,8 @@ function theme_authorize_report($variables) {
  * @param $variables
  *   An associative array containing:
  *   - message: The log message.
+ *     It's the caller's responsibility to ensure this string contains no
+ *     XSS holes.
  *   - success: A boolean indicating failure or success.
  *
  * @ingroup themeable
diff --git a/core/lib/Drupal/Component/Utility/String.php b/core/lib/Drupal/Component/Utility/String.php
index 9796a5f..1cc1e45 100644
--- a/core/lib/Drupal/Component/Utility/String.php
+++ b/core/lib/Drupal/Component/Utility/String.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Utility;
 
+use Drupal\Core\Template\SafeMarkup;
+
 /**
  * Provides helpers to operate on strings.
  *
@@ -22,7 +24,7 @@ class String {
    * @param string $text
    *   The text to be checked or processed.
    *
-   * @return string
+   * @return \Drupal\Core\Template\SafeMarkup
    *   An HTML safe version of $text, or an empty string if $text is not
    *   valid UTF-8.
    *
@@ -31,7 +33,7 @@ class String {
    * @see drupal_validate_utf8()
    */
   public static function checkPlain($text) {
-    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
+    return $text instanceof SafeMarkup ? $text : new SafeMarkup(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
   }
 
   /**
@@ -65,7 +67,8 @@ public static function decodeEntities($text) {
    * addition to formatting it.
    *
    * @param $string
-   *   A string containing placeholders.
+   *   A string containing placeholders. The string itself is not escaped, any
+   *   unsafe content must be in $args and inserted via placeholders.
    * @param $args
    *   An associative array of replacements to make. Occurrences in $string of
    *   any key in $args are replaced with the corresponding value, after
@@ -108,7 +111,7 @@ public static function format($string, array $args = array()) {
           // Pass-through.
       }
     }
-    return strtr($string, $args);
+    return new SafeMarkup(strtr($string, $args));
   }
 
   /**
@@ -123,7 +126,8 @@ public static function format($string, array $args = array()) {
    *   The formatted text (html).
    */
   public static function placeholder($text) {
-    return '<em class="placeholder">' . static::checkPlain($text) . '</em>';
+    return new SafeMarkup('<em class="placeholder">' . static::checkPlain($text) . '</em>');
   }
 
+
 }
diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php
index dc49913..dd0df76 100644
--- a/core/lib/Drupal/Component/Utility/Xss.php
+++ b/core/lib/Drupal/Component/Utility/Xss.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Utility;
 
+use Drupal\Core\Template\SafeMarkup;
+
 /**
  * Provides helper to filter for cross-site scripting.
  *
@@ -90,7 +92,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
     $splitter = function ($matches) use ($html_tags, $mode) {
       return static::split($matches[1], $html_tags, $mode);
     };
-    return preg_replace_callback('%
+    return new SafeMarkup(preg_replace_callback('%
       (
       <(?=[^a-zA-Z!/])  # a lone <
       |                 # or
@@ -99,7 +101,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
       <[^>]*(>|$)       # a string that starts with a <, up until the > or the end of the string
       |                 # or
       >                 # just a >
-      )%x', $splitter, $string);
+      )%x', $splitter, $string));
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php b/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
index eac0b62..b2f87df 100644
--- a/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
+++ b/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Ajax;
 
 use Drupal\Core\Page\HtmlFragment;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -36,9 +37,9 @@ public function render($content) {
       $content = $content->getContent();
     }
     // Most controllers return a render array, but some return a string.
-    if (!is_array($content)) {
+    if (is_string($content) || $content instanceof SafeMarkup) {
       $content = array(
-        '#markup' => $content,
+        '#markup' => (string) $content,
       );
     }
 
@@ -74,11 +75,9 @@ public function render($content) {
 
   /**
    * Wraps drupal_render().
-   *
-   * @todo: Remove as part of https://drupal.org/node/2182149
    */
   protected function drupalRender(&$elements, $is_recursive_call = FALSE) {
-    return drupal_render($elements, $is_recursive_call);
+    return (string) drupal_render($elements, $is_recursive_call);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Ajax/InsertCommand.php b/core/lib/Drupal/Core/Ajax/InsertCommand.php
index 9871ef2..e46eac0 100644
--- a/core/lib/Drupal/Core/Ajax/InsertCommand.php
+++ b/core/lib/Drupal/Core/Ajax/InsertCommand.php
@@ -57,7 +57,7 @@ class InsertCommand implements CommandInterface {
    */
   public function __construct($selector, $html, array $settings = NULL) {
     $this->selector = $selector;
-    $this->html = $html;
+    $this->html = (string) $html;
     $this->settings = $settings;
   }
 
diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php
index 9c0fba8..9185c06 100644
--- a/core/lib/Drupal/Core/Config/StorableConfigBase.php
+++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Schema\Ignore;
 use Drupal\Core\Config\Schema\SchemaIncompleteException;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\TypedData\Type\FloatInterface;
 use Drupal\Core\TypedData\Type\IntegerInterface;
@@ -169,6 +170,10 @@ protected function validateValue($key, $value) {
    *   Exception on unsupported/undefined data type deducted.
    */
   protected function castValue($key, $value) {
+    if ($value instanceof SafeMarkup) {
+      $value = (string) $value;
+    }
+
     $element = FALSE;
     try {
       $element = $this->getSchemaWrapper()->get($key);
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index fe23fb6..99784f7 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -101,7 +101,7 @@ public static function registerTwig(ContainerBuilder $container) {
         'cache' => drupal_installation_attempted() ? FALSE : Settings::get('twig_cache', TRUE),
         // @todo Remove in followup issue
         // @see http://drupal.org/node/1712444.
-        'autoescape' => FALSE,
+        'autoescape' => TRUE,
         'debug' => Settings::get('twig_debug', FALSE),
         'auto_reload' => Settings::get('twig_auto_reload', NULL),
       ))
diff --git a/core/lib/Drupal/Core/Database/Install/Tasks.php b/core/lib/Drupal/Core/Database/Install/Tasks.php
index c4d88d2..6d0dfe7 100644
--- a/core/lib/Drupal/Core/Database/Install/Tasks.php
+++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
@@ -92,14 +92,14 @@ protected function hasPdoDriver() {
    * Assert test as failed.
    */
   protected function fail($message) {
-    $this->results[$message] = FALSE;
+    $this->results[(string) $message] = FALSE;
   }
 
   /**
    * Assert test as a pass.
    */
   protected function pass($message) {
-    $this->results[$message] = TRUE;
+    $this->results[(string) $message] = TRUE;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php
index dbe2c78..8354bea 100644
--- a/core/lib/Drupal/Core/Extension/ThemeHandler.php
+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -626,6 +626,8 @@ public function getName($theme) {
     if (!isset($themes[$theme])) {
       throw new \InvalidArgumentException(String::format('Requested the name of a non-existing theme @theme', array('@theme' => $theme)));
     }
+    // @todo For testing please remove before commit.
+    return \Drupal::config('system.site')->get('name');
     return String::checkPlain($themes[$theme]->info['name']);
   }
 
diff --git a/core/lib/Drupal/Core/Form/OptGroup.php b/core/lib/Drupal/Core/Form/OptGroup.php
index f94d62d..21e9855 100644
--- a/core/lib/Drupal/Core/Form/OptGroup.php
+++ b/core/lib/Drupal/Core/Form/OptGroup.php
@@ -43,7 +43,7 @@ public static function flattenOptions(array $array) {
    */
   protected static function doFlattenOptions(array $array, array &$options) {
     foreach ($array as $key => $value) {
-      if (is_object($value)) {
+      if (is_object($value) && isset($value->option)) {
         static::doFlattenOptions($value->option, $options);
       }
       elseif (is_array($value)) {
diff --git a/core/lib/Drupal/Core/Page/HeadElement.php b/core/lib/Drupal/Core/Page/HeadElement.php
index 85055ad..70cf2b7 100644
--- a/core/lib/Drupal/Core/Page/HeadElement.php
+++ b/core/lib/Drupal/Core/Page/HeadElement.php
@@ -8,11 +8,12 @@
 namespace Drupal\Core\Page;
 
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * This class represents an HTML element that appears in the HEAD tag.
  */
-class HeadElement {
+class HeadElement extends SafeMarkup {
 
   /**
    * An array of attributes for this element.
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
index bd1b3b3..916e8bb 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Defines a chained translation implementation combining multiple translators.
@@ -140,7 +141,7 @@ public function translate($string, array $args = array(), array $options = array
     $string = $translation === FALSE ? $string : $translation;
 
     if (empty($args)) {
-      return $string;
+      return new SafeMarkup($string);
     }
     else {
       return String::format($string, $args);
@@ -168,20 +169,21 @@ public function formatPlural($count, $singular, $plural, array $args = array(),
     $index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
     if ($index == 0) {
       // Singular form.
-      return $translated_array[0];
+      $return = $translated_array[0];
     }
     else {
       if (isset($translated_array[$index])) {
         // N-th plural form.
-        return $translated_array[$index];
+        $return = $translated_array[$index];
       }
       else {
         // If the index cannot be computed or there's no translation, use
         // the second plural form as a fallback (which allows for most flexiblity
         // with the replaceable @count value).
-        return $translated_array[1];
+        $return = $translated_array[1];
       }
     }
+    return new SafeMarkup($return);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Template/Attribute.php b/core/lib/Drupal/Core/Template/Attribute.php
index ead5d05..7432b6d 100644
--- a/core/lib/Drupal/Core/Template/Attribute.php
+++ b/core/lib/Drupal/Core/Template/Attribute.php
@@ -31,7 +31,7 @@
  *  // Produces <cat class="cat black-cat white-cat black-white-cat" id="socks">
  * @endcode
  */
-class Attribute implements \ArrayAccess, \IteratorAggregate {
+class Attribute extends \Twig_Markup implements \ArrayAccess, \IteratorAggregate {
 
   /**
    * Stores the attribute data.
@@ -86,9 +86,12 @@ protected function createAttributeValue($name, $value) {
     elseif (is_bool($value)) {
       $value = new AttributeBoolean($name, $value);
     }
-    elseif (!is_object($value)) {
+    elseif (!is_object($value) || $value instanceof SafeMarkup) {
       $value = new AttributeString($name, $value);
     }
+    elseif (!method_exists($value, 'render')) {
+      throw new \Exception('boo!');
+    }
     return $value;
   }
 
diff --git a/core/lib/Drupal/Core/Template/AttributeArray.php b/core/lib/Drupal/Core/Template/AttributeArray.php
index 95e0ef3..4d8145f 100644
--- a/core/lib/Drupal/Core/Template/AttributeArray.php
+++ b/core/lib/Drupal/Core/Template/AttributeArray.php
@@ -66,7 +66,7 @@ public function offsetExists($offset) {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return String::checkPlain(implode(' ', $this->value));
+    return (string) String::checkPlain(implode(' ', $this->value));
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Template/AttributeBoolean.php b/core/lib/Drupal/Core/Template/AttributeBoolean.php
index 4e9ea67..b5a0957 100644
--- a/core/lib/Drupal/Core/Template/AttributeBoolean.php
+++ b/core/lib/Drupal/Core/Template/AttributeBoolean.php
@@ -42,7 +42,7 @@ public function render() {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return $this->value === FALSE ? '' : String::checkPlain($this->name);
+    return $this->value === FALSE ? '' : (string) String::checkPlain($this->name);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Template/AttributeString.php b/core/lib/Drupal/Core/Template/AttributeString.php
index 07211be..e1c69dc 100644
--- a/core/lib/Drupal/Core/Template/AttributeString.php
+++ b/core/lib/Drupal/Core/Template/AttributeString.php
@@ -30,7 +30,7 @@ class AttributeString extends AttributeValueBase {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return String::checkPlain($this->value);
+    return (string) String::checkPlain($this->value);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Template/SafeMarkup.php b/core/lib/Drupal/Core/Template/SafeMarkup.php
new file mode 100644
index 0000000..58d85c4
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/SafeMarkup.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Template\SafeMarkup.
+ */
+
+namespace Drupal\Core\Template;
+use Drupal\Component\Utility\String;
+
+/**
+ * A class marking strings as already escaped for XSS purposes.
+ */
+class SafeMarkup extends \Twig_Markup {
+
+  /**
+   * Constructs a SafeMarkup object.
+   *
+   * @param string $content
+   *   The callback function name.
+   */
+  public function __construct($content) {
+    parent::__construct((string) $content, 'utf-8');
+  }
+
+  /**
+   * @todo.
+   *
+   * @return \Drupal\Core\Template\SafeMarkup
+   */
+  public static function concat() {
+    return SafeMarkup::implode('', func_get_args());
+  }
+
+  /**
+   * @todo.
+   *
+   * @return \Drupal\Core\Template\SafeMarkup
+   */
+  public static function implode($delimiter, array $array) {
+    foreach ($array as $key => $string) {
+      if (!$string instanceof SafeMarkup) {
+        $array[$key] = String::checkPlain($string);
+      }
+    }
+    return new SafeMarkup(implode($delimiter, $array));
+  }
+
+  public static function strReplace($search, $replace, $subject, &$count = NULL) {
+    $safe = $subject instanceof SafeMarkup;
+    $replacement = str_replace($search, $replace, $subject, $count);
+    return $safe ? new SafeMarkup($replacement) : $replacement;
+  }
+
+  /**
+   * Renders the markup.
+   *
+   * @return string
+   *   The results of the callback function.
+   */
+  public function render() {
+    return $this->__toString();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php
index b547d95..231f3aa 100644
--- a/core/lib/Drupal/Core/Utility/LinkGenerator.php
+++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php
@@ -11,8 +11,9 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Path\AliasManagerInterface;
-use Drupal\Core\Template\Attribute;
 use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Url;
 
 /**
@@ -122,8 +123,7 @@ public function generateFromUrl($text, Url $url) {
 
     // Sanitize the link text if necessary.
     $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
-
-    return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
+    return new SafeMarkup('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>');
   }
 
   /**
diff --git a/core/modules/contextual/lib/Drupal/contextual/ContextualController.php b/core/modules/contextual/lib/Drupal/contextual/ContextualController.php
index aeee4a6..fcc47de 100644
--- a/core/modules/contextual/lib/Drupal/contextual/ContextualController.php
+++ b/core/modules/contextual/lib/Drupal/contextual/ContextualController.php
@@ -44,7 +44,10 @@ public function render(Request $request) {
         '#type' => 'contextual_links',
         '#contextual_links' => _contextual_id_to_links($id),
       );
-      $rendered[$id] = drupal_render($element);
+      // Cast any returned safe markup to string so that it is created
+      // as correct JSON.
+      // @todo Maybe check safeness and checkplain the results?
+      $rendered[$id] = (string) drupal_render($element);
     }
 
     return new JsonResponse($rendered);
diff --git a/core/modules/editor/tests/Drupal/editor/Tests/EditorXssFilter/StandardTest.php b/core/modules/editor/tests/Drupal/editor/Tests/EditorXssFilter/StandardTest.php
index 7927eef..cc3a884 100644
--- a/core/modules/editor/tests/Drupal/editor/Tests/EditorXssFilter/StandardTest.php
+++ b/core/modules/editor/tests/Drupal/editor/Tests/EditorXssFilter/StandardTest.php
@@ -551,7 +551,7 @@ public function providerTestFilterXss() {
    */
   public function testFilterXss($input, $expected_output) {
     $output = call_user_func($this->editorXssFilterClass . '::filterXss', $input, $this->format);
-    $this->assertSame($expected_output, $output);
+    $this->assertSame($expected_output, (string) $output);
   }
 
 }
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php
index e5ad209..9a5b732 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php
@@ -90,7 +90,7 @@ public function getSettableOptions(AccountInterface $account = NULL) {
     $return = array();
     foreach ($options as $bundle => $entity_ids) {
       $bundle_label = String::checkPlain($bundles[$bundle]['label']);
-      $return[$bundle_label] = $entity_ids;
+      $return[(string) $bundle_label] = $entity_ids;
     }
 
     return count($return) == 1 ? reset($return) : $return;
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index bdde395..2ce34f1 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -9,6 +9,7 @@
 use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /*
@@ -314,7 +315,7 @@ function field_cache_clear() {
  *   UTF-8.
  */
 function field_filter_xss($string) {
-  return Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags()));
+  return new SafeMarkup(Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags())));
 }
 
 /**
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
index 84b587a..9b1cdb8 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
@@ -7,12 +7,14 @@
 
 namespace Drupal\field\Plugin\views\field;
 
+use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FormatterPluginManager;
@@ -686,11 +688,11 @@ public function submitGroupByForm(&$form, &$form_state) {
   protected function renderItems($items) {
     if (!empty($items)) {
       if (!$this->options['group_rows']) {
-        return implode('', $items);
+        return SafeMarkup::implode('', $items);
       }
 
       if ($this->options['multi_type'] == 'separator') {
-        return implode(Xss::filterAdmin($this->options['separator']), $items);
+        return new SafeMarkup(implode(Xss::filterAdmin($this->options['separator']), $items));
       }
       else {
         $item_list = array(
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
index da98cd4..1ea1eb3 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -398,7 +399,7 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, Ent
 
         if (!empty($summary)) {
           $field_row['settings_summary'] = array(
-            '#markup' => '<div class="field-plugin-summary">' . implode('<br />', $summary) . '</div>',
+            '#markup' => '<div class="field-plugin-summary">' . SafeMarkup::implode('<br />', $summary) . '</div>',
             '#cell_attributes' => array('class' => array('field-plugin-summary-cell')),
           );
         }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php
index 0da1bf9..91f8d45 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\field_ui;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -117,7 +119,7 @@ public function buildRow(EntityInterface $field) {
         $usage[] = $this->bundles[$field->entity_type][$bundle]['label'];
       }
     }
-    $row['data']['usage'] = implode(', ', $usage);
+    $row['data']['usage'] = SafeMarkup::implode(', ', $usage);
     return $row;
   }
 
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index f9aa9f9..11b071b 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Returns HTML for an individual file upload widget.
@@ -125,7 +126,7 @@ function theme_file_widget_multiple($variables) {
       $row[] = $display;
     }
     $row[] = $weight;
-    $row[] = $operations;
+    $row[] = new SafeMarkup($operations);
     $rows[] = array(
       'data' => $row,
       'class' => isset($widget['#attributes']['class']) ? array_merge($widget['#attributes']['class'], array('draggable')) : array('draggable'),
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 47b72ef..4c41b78 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\file\Entity\File;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Unicode;
@@ -943,10 +944,10 @@ function file_save_upload($form_field_name, $validators = array(), $destination
           '#theme' => 'item_list',
           '#items' => $errors,
         );
-        $message .= drupal_render($item_list);
+        $message = SafeMarkup::concat($message, drupal_render($item_list));
       }
       else {
-        $message .= ' ' . array_pop($errors);
+        $message = SafeMarkup::concat($message, ' ', array_pop($errors));
       }
       drupal_set_message($message, 'error');
       $files[$i] = FALSE;
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 3efe9ad..cd17f6a 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -13,6 +13,7 @@
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\filter\FilterFormatInterface;
 use Drupal\filter\Plugin\FilterInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -419,7 +420,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE,
     \Drupal::cache('filter')->set($cache_id, $text, Cache::PERMANENT, array('filter_format' => $format->id()));
   }
 
-  return $text;
+  return new SafeMarkup($text);
 }
 
 /**
diff --git a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
index 08ad4c8..22980fa 100644
--- a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\filter\Plugin\FilterBase;
 
 /**
@@ -76,7 +77,7 @@ public function process($text, $langcode, $cache, $cache_id) {
         // caption.
         $filter_caption = array(
           '#theme' => 'filter_caption',
-          '#node' => $node->C14N(),
+          '#node' => new SafeMarkup($node->C14N()),
           '#tag' => $node->tagName,
           '#caption' => $caption,
           '#align' => $align,
diff --git a/core/modules/filter/templates/filter-guidelines.html.twig b/core/modules/filter/templates/filter-guidelines.html.twig
index 88a3b47..ecf9b94 100644
--- a/core/modules/filter/templates/filter-guidelines.html.twig
+++ b/core/modules/filter/templates/filter-guidelines.html.twig
@@ -20,6 +20,6 @@
  */
 #}
 <div{{ attributes }}>
-  <h4 class="label">{{ format.name|escape }}</h4>
+  <h4 class="label">{{ format.name }}</h4>
   {{ tips }}
 </div>
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index b075d93..7888e2b 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_requirements().
@@ -29,7 +30,9 @@ function node_requirements($phase) {
     $requirements['node_access'] = array(
       'title' => t('Node Access Permissions'),
       'value' => $value,
-      'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'),
+      // The results of t() is safe and so is the results of l(). Preserving
+      // safe object.
+      'description' => new SafeMarkup($description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild')),
     );
   }
   return $requirements;
diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module
index 53c182c..fd7341d 100644
--- a/core/modules/responsive_image/responsive_image.module
+++ b/core/modules/responsive_image/responsive_image.module
@@ -7,6 +7,7 @@
 
 use Drupal\breakpoint\Entity\Breakpoint;
 use \Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -190,7 +191,6 @@ function theme_responsive_image($variables) {
   }
 
   $sources = array();
-  $output = array();
 
   // Fallback image, output as source with media query.
   $sources[] = array(
@@ -234,6 +234,7 @@ function theme_responsive_image($variables) {
   }
 
   if (!empty($sources)) {
+    $output = array();
     $output[] = '<picture>';
 
     // Add source tags to the output.
@@ -253,7 +254,7 @@ function theme_responsive_image($variables) {
     }
 
     $output[] = '</picture>';
-    return implode("\n", $output);
+    return new SafeMarkup(implode("\n", $output));
   }
 }
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
index 299f305..2786a3a 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -155,7 +156,8 @@ public function buildForm(array $form, array &$form_state, $test_id = NULL) {
       $rows = array();
       foreach ($assertions as $assertion) {
         $row = array();
-        $row[] = $assertion->message;
+        // @todo Need to preserve safe markup, not create it.
+        $row[] = new SafeMarkup($assertion->message);
         $row[] = $assertion->message_group;
         $row[] = drupal_basename($assertion->file);
         $row[] = $assertion->line;
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestTestForm.php b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestTestForm.php
index e3876a5..466ea67 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestTestForm.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestTestForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * List tests arranged in groups that can be selected and run.
@@ -87,8 +88,8 @@ public function buildForm(array $form, array &$form_state) {
       'data' => array(
         'simpleTest' => array(
           'images' => array(
-            drupal_render($image_collapsed),
-            drupal_render($image_extended),
+            (string) drupal_render($image_collapsed),
+            (string) drupal_render($image_extended),
           ),
         ),
       ),
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 023cf8e..585c100 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -277,7 +277,7 @@ protected function assert($status, $message = '', $group = 'Other', array $calle
       'test_id' => $this->testId,
       'test_class' => get_class($this),
       'status' => $status,
-      'message' => $message,
+      'message' => (string) $message,
       'message_group' => $group,
       'function' => $caller['function'],
       'line' => $caller['line'],
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index a120883..b29f186 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -23,6 +23,7 @@
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\block\Entity\Block;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -1628,6 +1629,9 @@ protected function drupalGetAJAX($path, array $options = array(), array $headers
    */
   protected function drupalPostForm($path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL, $extra_post = NULL) {
     $submit_matches = FALSE;
+    if ($submit instanceof SafeMarkup) {
+      $submit = (string) $submit;
+    }
     $ajax = is_array($submit);
     if (isset($path)) {
       $this->drupalGet($path, $options);
@@ -2284,7 +2288,7 @@ protected function buildXPathQuery($xpath, array $args = array()) {
       // XPath 1.0 doesn't support a way to escape single or double quotes in a
       // string literal. We split double quotes out of the string, and encode
       // them separately.
-      if (is_string($value)) {
+      if (is_string($value) || $value instanceof SafeMarkup) {
         // Explode the text at the quote characters.
         $parts = explode('"', $value);
 
@@ -2759,7 +2763,7 @@ protected function assertRaw($raw, $message = '', $group = 'Other') {
     if (!$message) {
       $message = String::format('Raw "@raw" found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) !== FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) !== FALSE, $message, $group);
   }
 
   /**
@@ -2786,7 +2790,7 @@ protected function assertNoRaw($raw, $message = '', $group = 'Other') {
     if (!$message) {
       $message = String::format('Raw "@raw" not found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) === FALSE, $message, $group);
   }
 
   /**
@@ -2870,7 +2874,7 @@ protected function assertTextHelper($text, $message = '', $group, $not_exists) {
     if (!$message) {
       $message = !$not_exists ? String::format('"@text" found', array('@text' => $text)) : String::format('"@text" not found', array('@text' => $text));
     }
-    return $this->assert($not_exists == (strpos($this->plainTextContent, $text) === FALSE), $message, $group);
+    return $this->assert($not_exists == (strpos($this->plainTextContent, (string) $text) === FALSE), $message, $group);
   }
 
   /**
@@ -3684,6 +3688,7 @@ protected function assertMail($name, $value = '', $message = '', $group = 'E-mai
   protected function assertMailString($field_name, $string, $email_depth, $message = '', $group = 'Other') {
     $mails = $this->drupalGetMails();
     $string_found = FALSE;
+    $string = (string) $string;
     for ($i = count($mails) -1; $i >= count($mails) - $email_depth && $i >= 0; $i--) {
       $mail = $mails[$i];
       // Normalize whitespace, as we don't know what the mail system might have
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 914228e..1977a6e 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -523,7 +523,7 @@ function simpletest_test_get_all($module = NULL) {
             }
           }
 
-          $groups[$info['group']][$class] = $info;
+          $groups[(string) $info['group']][$class] = $info;
         }
       }
 
diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php
index d061495..180be27 100644
--- a/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/ModulesListForm.php
@@ -17,6 +17,7 @@
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Access\AccessManager;
 
@@ -162,7 +163,7 @@ public function buildForm(array $form, array &$form_state) {
         '#open' => TRUE,
         '#theme' => 'system_modules_details',
         '#header' => array(
-          array('data' => '<span class="visually-hidden">' . $this->t('Installed') . '</span>', 'class' => array('checkbox')),
+          array('data' => new SafeMarkup('<span class="visually-hidden">' . $this->t('Installed') . '</span>'), 'class' => array('checkbox')),
           array('data' => $this->t('Name'), 'class' => array('name')),
           array('data' => $this->t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)),
         ),
diff --git a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php
index 7438e48..b272148 100644
--- a/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/ModulesUninstallForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
index caa80a2..d3b21e3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
@@ -277,7 +277,8 @@ function testDrupalRenderBasics() {
     );
 
     foreach($types as $type) {
-      $this->assertIdentical(drupal_render($type['value']), $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().');
+      $value = drupal_render($type['value']);
+      $this->assertIdentical((string) $value, $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().');
     }
   }
 
@@ -394,14 +395,14 @@ function testDrupalRenderThemeArguments() {
       '#theme' => 'common_test_foo',
     );
     // Test that defaults work.
-    $this->assertEqual(drupal_render($element), 'foobar', 'Defaults work');
+    $this->assertEqual((string) drupal_render($element), 'foobar', 'Defaults work');
     $element = array(
       '#theme' => 'common_test_foo',
       '#foo' => $this->randomName(),
       '#bar' => $this->randomName(),
     );
     // Tests that passing arguments to the theme function works.
-    $this->assertEqual(drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
+    $this->assertEqual((string) drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
   }
 
   /**
@@ -470,7 +471,7 @@ function testDrupalRenderPostRenderCache() {
     $element = $test_element;
     $element['#markup'] = '<p>#cache disabled</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -486,7 +487,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_GET');
     $element['#markup'] = '<p>#cache enabled, GET</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -509,7 +510,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_GET');
     $element['#markup'] = '<p>#cache enabled, GET</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -526,7 +527,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_POST');
     $element['#markup'] = '<p>#cache enabled, POST</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -589,7 +590,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     );
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -635,7 +636,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     drupal_static_reset('_drupal_add_js');
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -647,7 +648,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     unset($test_element['#cache']);
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $expected_settings = $context_1 + $context_2 + $context_3;
@@ -667,7 +668,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent');
     $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child');
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -742,7 +743,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element = $test_element;
     $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent');
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -754,7 +755,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child');
     $element = $element['child'];
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $expected_settings = $context_2 + $context_3;
@@ -790,7 +791,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     drupal_static_reset('_drupal_add_js');
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['common_test'], $context, '#attached is modified; JavaScript setting is added to page.');
 
@@ -803,7 +804,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     $element = $test_element;
     $element['#cache'] = array('cid' => 'render_cache_placeholder_test_GET');
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -840,7 +841,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     $element = $test_element;
     $element['#cache'] = array('cid' => 'render_cache_placeholder_test_GET');
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -880,7 +881,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     drupal_static_reset('_drupal_add_js');
     $element = $container;
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['common_test'], $context, '#attached is modified; JavaScript setting is added to page.');
 
@@ -899,7 +900,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     $element['#children'] = drupal_render($child, TRUE);
     // Eventually, drupal_render() gets called on the root element.
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -996,7 +997,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     $child = &$element['test_element'];
     $element['#children'] = drupal_render($child, TRUE);
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 9ba1a1c..67664e9 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Recursively check compatibility.
@@ -231,7 +232,7 @@ function theme_system_modules_details($variables) {
 
     // Add the module label and expand/collapse functionalty.
     $col2 = '<label id="module-' . $key . '" for="' . $module['enable']['#id'] . '" class="module-name table-filter-text-source">' . drupal_render($module['name']) . '</label>';
-    $row[] = array('class' => array('module'), 'data' => $col2);
+    $row[] = array('class' => array('module'), 'data' => new SafeMarkup($col2));
 
     // Add the description, along with any modules it requires.
     $description = '';
@@ -259,9 +260,9 @@ function theme_system_modules_details($variables) {
     }
     $details = array(
       '#type' => 'details',
-      '#title' => '<span class="text"> ' . drupal_render($module['description']) . '</span>',
+      '#title' => new SafeMarkup('<span class="text"> ' . drupal_render($module['description']) . '</span>'),
       '#attributes' => array('id' => $module['enable']['#id'] . '-description'),
-      '#description' => $description,
+      '#description' => new SafeMarkup($description),
     );
     $col4 = drupal_render($details);
     $row[] = array('class' => array('description', 'expand'), 'data' => $col4);
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 6161819..dfff949 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -11,6 +11,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PublicStream;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_requirements().
@@ -57,7 +58,8 @@ function system_requirements($phase) {
   if (function_exists('phpinfo')) {
     $requirements['php'] = array(
       'title' => t('PHP'),
-      'value' => ($phase == 'runtime') ? $phpversion .' ('. l(t('more information'), 'admin/reports/status/php') .')' : $phpversion,
+      // $phpversion is safe and output of l() is safe, so this value is safe.
+      'value' => new SafeMarkup(($phase == 'runtime') ? $phpversion . ' (' . l(t('more information'), 'admin/reports/status/php') . ')' : $phpversion),
     );
   }
   else {
@@ -319,7 +321,8 @@ function system_requirements($phase) {
       'title' => t('Cron maintenance tasks'),
       'severity' => $severity,
       'value' => $summary,
-      'description' => $description
+      // @todo Needs to preserve safe markup.
+      'description' => new SafeMarkup($description),
     );
   }
   if ($phase != 'install') {
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 8feb47b..ae6ea8f 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\block\BlockPluginInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\user\UserInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use GuzzleHttp\Exception\RequestException;
diff --git a/core/modules/system/templates/block--system-branding-block.html.twig b/core/modules/system/templates/block--system-branding-block.html.twig
index 2a12c7a..4cf0f1a 100644
--- a/core/modules/system/templates/block--system-branding-block.html.twig
+++ b/core/modules/system/templates/block--system-branding-block.html.twig
@@ -23,7 +23,7 @@
   {% endif %}
   {% if site_name %}
     <div class="site-name">
-      <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name|e }}</a>
+      <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name }}</a>
     </div>
   {% endif %}
   {% if site_slogan %}
diff --git a/core/modules/system/templates/datetime.html.twig b/core/modules/system/templates/datetime.html.twig
index 25ef788..183b834 100644
--- a/core/modules/system/templates/datetime.html.twig
+++ b/core/modules/system/templates/datetime.html.twig
@@ -25,5 +25,4 @@
  * @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
  */
 #}
-{# @todo Revisit once http://drupal.org/node/1825952 is resolved. #}
-<time{{ attributes }}>{{ html ? text|raw : text|escape }}</time>
+<time{{ attributes }}>{{ html ? text|raw : text }}</time>
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 4b28c81..8936c27 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -6,6 +6,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
 use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Url;
 use Drupal\file\Entity\File;
 use Drupal\user\Entity\Role;
@@ -692,7 +693,7 @@ function theme_username($variables) {
     // We have a link path, so we should generate a link using l().
     // Additional classes may be added as array elements like
     // $variables['link_options']['attributes']['class'][] = 'myclass';
-    $output = l($variables['name'] . $variables['extra'], $variables['link_path'], $variables['link_options']);
+    $output = l(new SafeMarkup($variables['name'] . $variables['extra']), $variables['link_path'], $variables['link_options']);
   }
   else {
     // Modules may have added important attributes so they must be included
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
index cbff847..da8ddb1 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -236,7 +236,7 @@ public function getField($field = NULL) {
    * @param $type
    *   The type of sanitization needed. If not provided, String::checkPlain() is used.
    *
-   * @return string
+   * @return \Drupal\Core\Template\SafeMarkup
    *   Returns the safe value.
    */
   public function sanitizeValue($value, $type = NULL) {
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
index 482a032..5294e13 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -850,18 +851,18 @@ public function buildOptionsForm(&$form, &$form_state) {
       // Setup the tokens for fields.
       $previous = $this->getPreviousFieldLabels();
       foreach ($previous as $id => $label) {
-        $options[t('Fields')]["[$id]"] = $label;
+        $options[(string) t('Fields')]["[$id]"] = $label;
       }
       // Add the field to the list of options.
-      $options[t('Fields')]["[{$this->options['id']}]"] = $this->label();
+      $options[(string) t('Fields')]["[{$this->options['id']}]"] = $this->label();
 
       $count = 0; // This lets us prepare the key as we want it printed.
       foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
-        $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
-        $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
       }
 
-      $this->documentSelfTokens($options[t('Fields')]);
+      $this->documentSelfTokens($options[(string) t('Fields')]);
 
       // Default text.
       $output = '<p>' . t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>';
@@ -1172,6 +1173,10 @@ public function advancedRender(ResultRow $values) {
         $this->last_render = $this->renderText($alter);
       }
     }
+    // @TODO: this is very dicey!
+    if ($this->last_render && is_string($this->last_render)) {
+      $this->last_render = new SafeMarkup($this->last_render);
+    }
 
     return $this->last_render;
   }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
index 902b543..42b8d0b 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
@@ -1159,8 +1159,7 @@ protected function prepareFilterSelectOptions(&$options) {
         $this->prepareFilterSelectOptions($options[$value]);
       }
       // FAPI has some special value to allow hierarchy.
-      // @see _form_options_flatten
-      elseif (is_object($label)) {
+      elseif (is_object($label) && isset($options[$value]->option)) {
         $this->prepareFilterSelectOptions($options[$value]->option);
       }
       else {
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 216bc93..5a93d2e 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -14,6 +14,7 @@
 use Drupal\Core\Database\Query\AlterableInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Plugin\Derivative\ViewsLocalTask;
 use Drupal\Core\Template\AttributeArray;
 use Drupal\views\ViewExecutable;
@@ -903,7 +904,7 @@ function views_pre_render_views_form_views_form($element) {
   }
 
   // Apply substitutions to the rendered output.
-  $element['output']['#markup'] = str_replace($search, $replace, $element['output']['#markup']);
+  $element['output']['#markup'] = SafeMarkup::strReplace($search, $replace, $element['output']['#markup']);
 
   // Sort, render and add remaining form fields.
   $children = Element::children($element, TRUE);
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 86e3e85..6690a81 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Form\ViewsForm;
 use Drupal\views\ViewExecutable;
 
@@ -525,6 +526,7 @@ function template_preprocess_views_view_table(&$variables) {
 
     // Render the header labels.
     if ($field == $column && empty($fields[$field]->options['exclude'])) {
+      $safe = TRUE;
       $label = String::checkPlain(!empty($fields[$field]) ? $fields[$field]->label() : '');
       if (empty($options['info'][$field]['sortable']) || !$fields[$field]->clickSortable()) {
         $variables['header'][$field]['content'] = $label;
@@ -542,7 +544,10 @@ function template_preprocess_views_view_table(&$variables) {
             '#theme' => 'tablesort_indicator',
             '#style' => $initial,
           );
-          $label .= drupal_render($tablesort_indicator);
+          $markup = drupal_render($tablesort_indicator);
+          // $label is safe.
+          $safe = $markup instanceof SafeMarkup;
+          $label .= $markup;
         }
 
         $query['order'] = $field;
@@ -552,7 +557,7 @@ function template_preprocess_views_view_table(&$variables) {
           'attributes' => array('title' => $title),
           'query' => $query,
         );
-        $variables['header'][$field]['content'] = l($label, current_path(), $link_options);
+        $variables['header'][$field]['content'] = l($safe ? new SafeMarkup($label) : $label, current_path(), $link_options);
       }
 
       // Set up the header label class.
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index e90ef35..3fe9789 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Tags;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
@@ -89,16 +90,18 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa
   // always give the button a unique #value, rather than playing around with
   // #name.
   $button_title = !empty($triggering_element['#title']) ? $triggering_element['#title'] : $trigger_key;
-  if (empty($seen_buttons[$button_title])) {
-    $wrapping_element[$button_key]['#value'] = t('Update "@title" choice', array(
+  $button_title_string = (string) $button_title;
+  if (empty($seen_buttons[$button_title_string])) {
+    // This code relies on check_plain()'ing the string because of the quotes.
+    $wrapping_element[$button_key]['#value'] = (string) t('Update "@title" choice', array(
       '@title' => $button_title,
     ));
-    $seen_buttons[$button_title] = 1;
+    $seen_buttons[$button_title_string] = 1;
   }
   else {
-    $wrapping_element[$button_key]['#value'] = t('Update "@title" choice (@number)', array(
+    $wrapping_element[$button_key]['#value'] = (string) t('Update "@title" choice (@number)', array(
       '@title' => $button_title,
-      '@number' => ++$seen_buttons[$button_title],
+      '@number' => ++$seen_buttons[$button_title_string],
     ));
   }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php b/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php
index a09b063..735c95d 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\ViewExecutable;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\Views;
@@ -92,7 +93,7 @@ public function reportFields() {
       foreach ($views as $view) {
         $rows[$field_name]['data'][1][] = $this->l($view, 'views_ui.edit', array('view' => $view));
       }
-      $rows[$field_name]['data'][1] = implode(', ', $rows[$field_name]['data'][1]);
+      $rows[$field_name]['data'][1] = SafeMarkup::implode(', ', $rows[$field_name]['data'][1]);
     }
 
     // Sort rows by field name.
@@ -120,7 +121,7 @@ public function reportPlugins() {
       foreach ($row['views'] as $row_name => $view) {
         $row['views'][$row_name] = $this->l($view, 'views_ui.edit', array('view' => $view));
       }
-      $row['views'] = implode(', ', $row['views']);
+      $row['views'] = SafeMarkup::implode(', ', $row['views']);
     }
 
     // Sort rows by field name.
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
index 68ad5b0..a468589 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
@@ -230,7 +230,7 @@ protected function getDisplaysList(EntityInterface $view) {
     foreach ($view->get('display') as $display) {
       $definition = $this->displayManager->getDefinition($display['display_plugin']);
       if (!empty($definition['admin'])) {
-        $displays[$definition['admin']] = TRUE;
+        $displays[(string) $definition['admin']] = TRUE;
       }
     }
 
diff --git a/core/themes/bartik/templates/block--system-branding-block.html.twig b/core/themes/bartik/templates/block--system-branding-block.html.twig
index 5917f58..f6147a6 100644
--- a/core/themes/bartik/templates/block--system-branding-block.html.twig
+++ b/core/themes/bartik/templates/block--system-branding-block.html.twig
@@ -23,7 +23,7 @@
     <div class="site-branding-text">
       {% if site_name %}
         <strong class="site-name">
-          <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name|e }}</a>
+          <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name }}</a>
         </strong>
       {% endif %}
       {% if site_slogan %}
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
index 1595bf8..47376dc 100644
--- a/core/themes/engines/twig/twig.engine
+++ b/core/themes/engines/twig/twig.engine
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_theme().
@@ -93,7 +94,7 @@ function twig_render_template($template_file, $variables) {
     $output['debug_info']   .= "\n<!-- BEGIN OUTPUT from '{$template_file}' -->\n";
     $output['debug_suffix'] .= "\n<!-- END OUTPUT from '{$template_file}' -->\n\n";
   }
-  return implode('', $output);
+  return new SafeMarkup(implode('', $output));
 }
 
 /**
diff --git a/core/update.php b/core/update.php
index b6accf3..1446219 100644
--- a/core/update.php
+++ b/core/update.php
@@ -17,6 +17,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Update\Form\UpdateScriptSelectionForm;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Core.php b/core/vendor/twig/twig/lib/Twig/Extension/Core.php
index 4e80c67..396a9f3 100644
--- a/core/vendor/twig/twig/lib/Twig/Extension/Core.php
+++ b/core/vendor/twig/twig/lib/Twig/Extension/Core.php
@@ -922,7 +922,12 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
 
     if (!is_string($string)) {
         if (is_object($string) && method_exists($string, '__toString')) {
-            $string = (string) $string;
+            // @todo Move to twig engine. This is necessary because of
+            // RenderWrapper.
+            $string = $string->__toString();
+            if ($autoescape && $string instanceof Twig_Markup) {
+              return $string;
+            }
         } else {
             return $string;
         }
