diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php
index 69d12fe..2d5b22a 100644
--- a/core/lib/Drupal/Component/Utility/SafeMarkup.php
+++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
@@ -91,7 +91,7 @@ public static function set($string, $strategy = 'html') {
    *   TRUE if the string has been marked secure, FALSE otherwise.
    */
   public static function isSafe($string, $strategy = 'html') {
-    return isset(static::$safeStrings[(string) $string][$strategy]) ||
+    return $string instanceOf SafeStringInterface || isset(static::$safeStrings[(string) $string][$strategy]) ||
       isset(static::$safeStrings[(string) $string]['all']);
   }
 
diff --git a/core/lib/Drupal/Component/Utility/SafeStringInterface.php b/core/lib/Drupal/Component/Utility/SafeStringInterface.php
new file mode 100644
index 0000000..f078faa
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/SafeStringInterface.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\SafeStringInterface.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Marks an objects __toString() method as returning safe markup.
+ */
+interface SafeStringInterface {
+}
diff --git a/core/lib/Drupal/Core/Template/Attribute.php b/core/lib/Drupal/Core/Template/Attribute.php
index ad4e1b1..b8c0590 100644
--- a/core/lib/Drupal/Core/Template/Attribute.php
+++ b/core/lib/Drupal/Core/Template/Attribute.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Template;
 
-use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\SafeStringInterface;
 
 /**
  * Collects, sanitizes, and renders HTML attributes.
@@ -42,8 +42,7 @@
  * The attribute keys and values are automatically sanitized for output with
  * htmlspecialchars() and the entire attribute string is marked safe for output.
  */
-class Attribute implements \ArrayAccess, \IteratorAggregate {
-
+class Attribute implements \ArrayAccess, \IteratorAggregate, SafeStringInterface {
   /**
    * Stores the attribute data.
    *
@@ -259,10 +258,7 @@ public function __toString() {
         $return .= ' ' . $rendered;
       }
     }
-    // The implementations of AttributeValueBase::render() call
-    // htmlspecialchars() on the attribute name and value so we are confident
-    // that the return value can be set as safe.
-    return SafeMarkup::set($return);
+    return $return;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php
index 99e807a..dce7832 100644
--- a/core/lib/Drupal/Core/Template/TwigExtension.php
+++ b/core/lib/Drupal/Core/Template/TwigExtension.php
@@ -13,6 +13,7 @@
 namespace Drupal\Core\Template;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\SafeStringInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Theme\ThemeManagerInterface;
@@ -382,7 +383,7 @@ public function escapeFilter(\Twig_Environment $env, $arg, $strategy = 'html', $
     }
 
     // Keep Twig_Markup objects intact to support autoescaping.
-    if ($autoescape && $arg instanceOf \Twig_Markup) {
+    if ($autoescape && ($arg instanceOf \Twig_Markup || $arg instanceOf SafeStringInterface)) {
       return $arg;
     }
 
