diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 4d441f2..ae8e00b 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1078,7 +1078,10 @@ function template_preprocess_item_list(&$variables) {
  *   - title: A descriptive title of the feed.
  */
 function template_preprocess_feed_icon(&$variables) {
-  $text = t('Subscribe to !feed-title', array('!feed-title' => $variables['title']));
+  // Stripping tags because that's what l() used to do.
+  $title = strip_tags($variables['title']);
+  $text = t('Subscribe to @feed-title', array('@feed-title' => $title));
+  $variables['attributes']['title'] = $text;
   $variables['icon'] = array(
     '#theme' => 'image__feed_icon',
     '#uri' => 'core/misc/feed.png',
@@ -1086,8 +1089,6 @@ function template_preprocess_feed_icon(&$variables) {
     '#height' => 16,
     '#alt' => $text,
   );
-  // Stripping tags because that's what l() used to do.
-  $variables['attributes']['title'] = strip_tags($text);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Template/AttributeString.php b/core/lib/Drupal/Core/Template/AttributeString.php
index 2dff59b..2a71473 100644
--- a/core/lib/Drupal/Core/Template/AttributeString.php
+++ b/core/lib/Drupal/Core/Template/AttributeString.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Template;
 
+use Drupal\Component\Utility\SafeMarkup;
+
 /**
  * A class that represents most standard HTML attributes.
  *
@@ -28,7 +30,13 @@ class AttributeString extends AttributeValueBase {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return htmlspecialchars($this->value, ENT_QUOTES, 'UTF-8');
+    if (SafeMarkup::isSafe($this->value)) {
+      // Only replace double quotes so we don't break the attribute.
+      return str_replace('"', '&quot;', $this->value);
+    }
+    else {
+      return htmlspecialchars($this->value, ENT_QUOTES, 'UTF-8');
+    }
   }
 
 }
diff --git a/core/lib/Drupal/Core/Template/AttributeValueBase.php b/core/lib/Drupal/Core/Template/AttributeValueBase.php
index c037004..11cb3c6 100644
--- a/core/lib/Drupal/Core/Template/AttributeValueBase.php
+++ b/core/lib/Drupal/Core/Template/AttributeValueBase.php
@@ -7,12 +7,14 @@
 
 namespace Drupal\Core\Template;
 
+use Drupal\Component\Utility\SafeStringInterface;
+
 /**
  * Defines the base class for an attribute type.
  *
  * @see \Drupal\Core\Template\Attribute
  */
-abstract class AttributeValueBase {
+abstract class AttributeValueBase implements SafeStringInterface {
 
   /**
    * Renders '$name=""' if $value is an empty string.
diff --git a/core/tests/Drupal/Tests/Core/Template/AttributeTest.php b/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
index b4a192d..b6f29f4 100644
--- a/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
+++ b/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
@@ -7,9 +7,11 @@
 
 namespace Drupal\Tests\Core\Template;
 
+use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Template\AttributeArray;
 use Drupal\Core\Template\AttributeString;
+use Drupal\Core\Template\TwigExtension;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -420,4 +422,60 @@ public function testStorage() {
     $this->assertEquals(array('class' => new AttributeArray('class', array('example-class'))), $attribute->storage());
   }
 
+  /**
+   * Test attribute escaping.
+   */
+  public function testAttributeEscaping() {
+    $attributes = new Attribute(['title' => '<span>tag</span>&\'"']);
+
+    // Entire attribute escaping.
+    $result = (string) $attributes;
+    $this->assertEquals(' title="&lt;span&gt;tag&lt;/span&gt;&amp;&#039;&quot;"', $result);
+
+    // Attribute value escaping.
+    $result = (string) $attributes['title'];
+    $this->assertEquals('&lt;span&gt;tag&lt;/span&gt;&amp;&#039;&quot;', $result);
+
+    $attributes = new Attribute(['title' => SafeMarkup::set('<span>tag</span>&\'"')]);
+    // Entire attribute escaping with safe values.
+    $result = (string) $attributes;
+    $this->assertEquals(' title="<span>tag</span>&\'"&quot;"', $result);
+
+    // Attribute value escaping with safe values.
+    $result = (string) $attributes['title'];
+    $this->assertEquals('<span>tag</span>&\'&quot;', $result);
+  }
+
+  /**
+   * Tests the twig escaping Attribute.
+   */
+  public function testTwigAttributeEscaping() {
+    $loader = new \Twig_Loader_String();
+    $twig = new \Twig_Environment($loader);
+    $renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
+    $twig->addExtension(new TwigExtension($renderer));
+
+    $attributes = new Attribute(['title' => '<span>tag</span>&\'"']);
+    $context = ['attributes' =>  $attributes];
+
+    // Entire attribute escaping.
+    $result = $twig->render('{{ attributes }}', $context);
+    $this->assertEquals(' title="&lt;span&gt;tag&lt;/span&gt;&amp;&#039;&quot;"', $result);
+
+    // Attribute value escaping.
+    $result = $twig->render('{{ attributes.title }}', $context);
+    $this->assertEquals('&lt;span&gt;tag&lt;/span&gt;&amp;&#039;&quot;', $result);
+
+    $attributes = new Attribute(['title' => SafeMarkup::set('<span>tag</span>&\'"')]);
+    $context = ['attributes' =>  $attributes];
+
+    // Entire attribute escaping with safe values.
+    $result = $twig->render('{{ attributes }}', $context);
+    $this->assertEquals(' title="<span>tag</span>&\'&quot;"', $result);
+
+    // Attribute value escaping with safe values.
+    $result = $twig->render('{{ attributes.title }}', $context);
+    $this->assertEquals('<span>tag</span>&\'&quot;', $result);
+  }
+
 }
