diff --git a/app/code/Magento/Backend/Block/Widget/Button/SplitButton.php b/app/code/Magento/Backend/Block/Widget/Button/SplitButton.php
index e2e83457a571c33cb2cf73ec62cdaa1338a3940a..d2603eebad675005569bec73614a4bccc2e23263 100644
--- a/app/code/Magento/Backend/Block/Widget/Button/SplitButton.php
+++ b/app/code/Magento/Backend/Block/Widget/Button/SplitButton.php
@@ -229,7 +229,7 @@ class SplitButton extends \Magento\Backend\Block\Widget
             if ($attributeValue === null || $attributeValue == '') {
                 continue;
             }
-            $html[] = $attributeKey . '="' . htmlspecialchars($attributeValue, ENT_COMPAT, 'UTF-8', false) . '"';
+            $html[] = $attributeKey . '="' . $this->escapeHtmlAttr($attributeValue, false) . '"';
         }
         return join(' ', $html);
     }
diff --git a/app/code/Magento/Ui/Component/Control/Button.php b/app/code/Magento/Ui/Component/Control/Button.php
index 5e407d93e3959b5ff5a0320f75e765e85a704097..fda9a104e037783a0a23a61d6be851caa6902a5e 100644
--- a/app/code/Magento/Ui/Component/Control/Button.php
+++ b/app/code/Magento/Ui/Component/Control/Button.php
@@ -134,7 +134,7 @@ class Button extends Template implements ControlInterface
             if ($attributeValue === null || $attributeValue == '') {
                 continue;
             }
-            $html .= $attributeKey . '="' . htmlspecialchars($attributeValue, ENT_COMPAT, 'UTF-8', false) . '" ';
+            $html .= $attributeKey . '="' . $this->escapeHtmlAttr($attributeValue, false) . '" ';
         }
 
         return $html;
diff --git a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
index 418e3975d2aa25eb0a8232257b543d8eb621ad9b..6158b6adc3a68c0bdee43f03d31e0400ceddf0e9 100644
--- a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
+++ b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
@@ -77,10 +77,10 @@ var pageGroupTemplate = '<div class="fieldset-wrapper page_group_container" id="
             '<p>' +
                 '<input disabled="disabled" type="text" class="input-text entities" name="widget_instance[<%- data.id %>][<?php /* @escapeNotVerified */ echo $container['name'] ?>][entities]" value="<%- data.<?php /* @escapeNotVerified */ echo $container['name'] ?>_entities %>" readonly="readonly" />&nbsp;' +
                 '<a class="widget-option-chooser" href="javascript:void(0)" onclick="WidgetInstance.displayEntityChooser(\'<?php /* @escapeNotVerified */ echo $container['code'] ?>\', \'<?php /* @escapeNotVerified */ echo $container['name'] ?>_ids_<%- data.id %>\')"  title="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Open Chooser')) ?>">' +
-                    '<img src="<?php /* @escapeNotVerified */ echo $block->getViewFileUrl('images/rule_chooser_trigger.gif') ?>" alt="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Open Chooser')); ?>" />' +
+                    '<img src="<?php echo $block->getViewFileUrl('images/rule_chooser_trigger.gif') ?>" alt="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Open Chooser')); ?>" />' +
                 '</a>&nbsp;' +
                 '<a href="javascript:void(0)" onclick="WidgetInstance.hideEntityChooser(\'<?php /* @escapeNotVerified */ echo $container['name'] ?>_ids_<%- data.id %>\')" title="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Apply')); ?>">' +
-                    '<img src="<?php /* @escapeNotVerified */ echo $block->getViewFileUrl('images/rule_component_apply.gif') ?>" alt="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Apply')); ?>" />' +
+                    '<img src="<?php echo $block->getViewFileUrl('images/rule_component_apply.gif') ?>" alt="<?php /* @escapeNotVerified */ echo $block->escapeJs(__('Apply')); ?>" />' +
                 '</a>' +
             '</p>'+
             '<div class="chooser"></div>'+
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
index bc1c4466f626f8ba7b69579d6b2edb8710a787c6..cc7015e3f9902505e2115cfb7dab9e6d025a4d93 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
@@ -273,7 +273,7 @@ class AccountTest extends \Magento\TestFramework\TestCase\AbstractController
             $this->equalTo([
                 'You must confirm your account. Please check your email for the confirmation link or '
                     . '<a href="http://localhost/index.php/customer/account/confirmation/email/'
-                    . rawurlencode($email) . '/">click here</a> for a new link.'
+                    . 'test2%40email.com/">click here</a> for a new link.'
             ]),
             MessageInterface::TYPE_SUCCESS
         );
diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml
index 56fb9a9e46bbd7024d20439cdd71cf46a13d1250..0a83ed0168f4320dd6df391ecd7be186ee146f7a 100644
--- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml
+++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml
@@ -12,7 +12,6 @@
 <input name="form_key" type="hidden" value="<?php echo $block->escapeUrl($var) ?>" />
 <input name="form_key" type="hidden" value="<?php echo $block->escapeHtmlAttr('value') ?>" />
 <input name="form_key" type="hidden" value="<?php echo $block->escapeJs('value') ?>" />
-<input name="form_key" type="hidden" value="<?php echo $block->escapeXssInUrl("some value") ?>" />
 echo $var;
 <?php echo $block->getHtmlId("some value") ?>
 <?php echo $block->getIdHtml("some value") ?>
diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php
index 312e61bb6e4b3094ece8fe0d68f242613a7ac263..ecedd676a5601995f1a0a382d550a4a4541e78f5 100644
--- a/lib/internal/Magento/Framework/Escaper.php
+++ b/lib/internal/Magento/Framework/Escaper.php
@@ -48,11 +48,15 @@ class Escaper
      * Escape a string for the HTML attribute context
      *
      * @param string $string
+     * @param boolean $escapeSingleQuote
      * @return string
      */
-    public function escapeHtmlAttr($string)
+    public function escapeHtmlAttr($string, $escapeSingleQuote = true)
     {
-        return $this->getEscaper()->escapeHtmlAttr($string);
+        if ($escapeSingleQuote) {
+            return $this->getEscaper()->escapeHtmlAttr($string);
+        }
+        return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
     }
 
     /**
@@ -66,6 +70,28 @@ class Escaper
         return $this->escapeHtml($this->escapeXssInUrl($string));
     }
 
+    /**
+     * Encode URL
+     *
+     * @param string $string
+     * @return string
+     */
+    public function encodeUrlParam($string)
+    {
+        return $this->getEscaper()->escapeUrl($string);
+    }
+
+    /**
+     * Encode JSON
+     *
+     * @param array $data
+     * @return string
+     */
+    public function encodeJSON($data)
+    {
+        return json_encode($data, JSON_HEX_QUOT | JSON_HEX_APOS);
+    }
+
     /**
      * Escape string for the JavaScript context
      *
diff --git a/lib/internal/Magento/Framework/Url.php b/lib/internal/Magento/Framework/Url.php
index 1e5de34ad27bc8916f01f84c12e084eeaa099ef9..5ab006dc70275258ed0f5d54527bbd19eb6a5e8a 100644
--- a/lib/internal/Magento/Framework/Url.php
+++ b/lib/internal/Magento/Framework/Url.php
@@ -174,7 +174,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur
     private $urlModifier;
 
     /**
-     * @var \Magento\Framework\ZendEscaper
+     * @var \Magento\Framework\Escaper
      */
     private $escaper;
 
@@ -933,7 +933,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur
         }
 
         if (!is_null($fragment)) {
-            $url .= '#' . $this->getEscaper()->escapeUrl($fragment);
+            $url .= '#' . $this->getEscaper()->encodeUrlParam($fragment);
         }
         $this->getRouteParamsResolver()->unsetData('secure');
         $this->getRouteParamsResolver()->unsetData('escape_params');
@@ -988,7 +988,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur
 
         $fragment = $this->_getFragment();
         if ($fragment) {
-            $url .= '#' . $this->getEscaper()->escapeUrl($fragment);
+            $url .= '#' . $this->getEscaper()->encodeUrlParam($fragment);
         }
 
         return $url;
@@ -1182,7 +1182,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur
     {
         if ($this->escaper == null) {
             $this->escaper = \Magento\Framework\App\ObjectManager::getInstance()
-                    ->get(\Magento\Framework\ZendEscaper::class);
+                    ->get(\Magento\Framework\Escaper::class);
         }
         return $this->escaper;
     }
diff --git a/lib/internal/Magento/Framework/Url/RouteParamsResolver.php b/lib/internal/Magento/Framework/Url/RouteParamsResolver.php
index 3c37ef27a7a28afae6f58ae78f28bcb3842da284..d6d0bd383ffb44bb509aa06514e94d9eedb7107c 100644
--- a/lib/internal/Magento/Framework/Url/RouteParamsResolver.php
+++ b/lib/internal/Magento/Framework/Url/RouteParamsResolver.php
@@ -32,7 +32,7 @@ class RouteParamsResolver extends \Magento\Framework\DataObject implements Route
     protected $queryParamsResolver;
 
     /**
-     * @var \Magento\Framework\ZendEscaper
+     * @var \Magento\Framework\Escaper
      */
     protected $escaper;
 
@@ -112,15 +112,15 @@ class RouteParamsResolver extends \Magento\Framework\DataObject implements Route
             } else {
                 if (is_object($value)) {
                     if ($this->getData('escape_params')) {
-                        $this->setRouteParam($this->getEscaper()->escapeUrl($key), $value);
+                        $this->setRouteParam($this->getEscaper()->encodeUrlParam($key), $value);
                     } else {
                         $this->setRouteParam($key, $value);
                     }
                 } else {
                     if ($this->getData('escape_params')) {
                         $this->setRouteParam(
-                            $this->getEscaper()->escapeUrl($key),
-                            $this->getEscaper()->escapeUrl($value)
+                            $this->getEscaper()->encodeUrlParam($key),
+                            $this->getEscaper()->encodeUrlParam($value)
                         );
                     } else {
                         $this->setRouteParam($key, $value);
@@ -166,14 +166,14 @@ class RouteParamsResolver extends \Magento\Framework\DataObject implements Route
      * Get escaper
      *
      * @param void
-     * @return \Magento\Framework\ZendEscaper
+     * @return \Magento\Framework\Escaper
      * @deprecated
      */
     private function getEscaper()
     {
         if ($this->escaper == null) {
             $this->escaper = \Magento\Framework\App\ObjectManager::getInstance()
-                    ->get(\Magento\Framework\ZendEscaper::class);
+                    ->get(\Magento\Framework\Escaper::class);
         }
         return $this->escaper;
     }
diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
index 3e21ff1b762f84019bb8900e85aa087eabd3946f..3a1b69dc64097dc04f44f6b75a1ef670b1f8bf4d 100644
--- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
+++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
@@ -891,11 +891,23 @@ abstract class AbstractBlock extends \Magento\Framework\DataObject implements Bl
      * Escape a string for the HTML attribute context
      *
      * @param string $string
+     * @param boolean $escapeSingleQuote
      * @return string
      */
-    public function escapeHtmlAttr($string)
+    public function escapeHtmlAttr($string, $escapeSingleQuote = true)
     {
-        return $this->_escaper->escapeHtmlAttr($string);
+        return $this->_escaper->escapeHtmlAttr($string, $escapeSingleQuote);
+    }
+
+    /**
+     * Encode JSON
+     *
+     * @param array $data
+     * @return string
+     */
+    public function encodeJSON($data)
+    {
+        return $this->_escaper->encodeJSON($data);
     }
 
     /**