diff --git a/CHANGES.rst b/CHANGES.rst
index 971d377..3e0901e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -3,6 +3,8 @@
 
 - Add nextUntil method
 
+- Fix escaping of top-level element text in ``.html()`` output
+
 
 1.4.3 (2020-11-21)
 ------------------
diff --git a/pyquery/pyquery.py b/pyquery/pyquery.py
index e549f0e..976a158 100644
--- a/pyquery/pyquery.py
+++ b/pyquery/pyquery.py
@@ -8,6 +8,7 @@ from urllib.parse import urljoin
 from .openers import url_opener
 from .text import extract_text
 from copy import deepcopy
+from html import escape
 from lxml import etree
 import lxml.html
 import inspect
@@ -1085,9 +1086,9 @@ class PyQuery(list):
                 return None
             tag = self[0]
             children = tag.getchildren()
+            html = escape(tag.text or '', quote=False)
             if not children:
-                return tag.text or ''
-            html = tag.text or ''
+                return html
             if 'encoding' not in kwargs:
                 kwargs['encoding'] = str
             html += u''.join([etree.tostring(e, **kwargs)

diff --git a/tests/test_pyquery.py b/tests/test_pyquery.py
index d82a556..340e11e 100644
--- a/tests/test_pyquery.py
+++ b/tests/test_pyquery.py
@@ -534,9 +534,10 @@ Bacon</textarea>
         self.assertEqual(d('#textarea-multi').val(), multi_expected)
         self.assertEqual(d('#textarea-multi').text(), multi_expected)
         multi_new = '''Bacon\n<b>Eggs</b>\nSpam'''
+        multi_new_expected = '''Bacon\n&lt;b&gt;Eggs&lt;/b&gt;\nSpam'''
         d('#textarea-multi').val(multi_new)
-        self.assertEqual(d('#textarea-multi').val(), multi_new)
-        self.assertEqual(d('#textarea-multi').text(), multi_new)
+        self.assertEqual(d('#textarea-multi').val(), multi_new_expected)
+        self.assertEqual(d('#textarea-multi').text(), multi_new_expected)
 
     def test_val_for_select(self):
         d = pq(self.html4)
@@ -622,6 +623,13 @@ Bacon</textarea>
         self.assertEqual(new_html, expected)
         self.assertIn(replacement, new_html)
 
+    def test_html_escape(self):
+        inner_html = 'encoded &lt;script&gt; tag with "quotes".' \
+                     '<span>nested &lt;tag&gt;</span>'
+        html = '<div>' + inner_html + '</div>'
+        d = pq(html)
+        self.assertEqual(d.html(), inner_html)
+
 
 class TestAjax(TestCase):
 

.html() fails to escape initial html entities
The html() method returns incorrect results in some cases because it fails to escape HTML entities prior to the first tag in the inner HTML:

```
>>> PyQuery("<foo>&lt;script&gt;// uh oh&lt;/script&gt;bar<boo/></foo>").html()
'<script>// uh oh</script>bar<boo/>'
```

This has potential security implications for downstream users if processing sanitized user-controlled content.

The fix would be to html-encode `tag.text` in [the html method](https://github.com/gawel/pyquery/blob/8f2a788647c7260357e4f76fd1a19a35aa26cdee/pyquery/pyquery.py#L1068).
tests/test_pyquery.py::TestManipulating::test_html_escape tests/test_pyquery.py::TestManipulating::test_val_for_textarea
tests/test_pyquery.py::TestUnicode::test_unicode tests/test_pyquery.py::TestAttributeCase::test_html_upper_element_name tests/test_pyquery.py::TestAttributeCase::test_xml_upper_element_name tests/test_pyquery.py::TestSelector::test_class tests/test_pyquery.py::TestSelector::test_get_root tests/test_pyquery.py::TestSelector::test_on_the_fly_dom_creation tests/test_pyquery.py::TestSelector::test_pseudo_classes tests/test_pyquery.py::TestSelector::test_selector_from_doc tests/test_pyquery.py::TestSelector::test_selector_from_html tests/test_pyquery.py::TestSelector::test_selector_from_html_from_obj tests/test_pyquery.py::TestSelector::test_selector_from_obj tests/test_pyquery.py::TestTraversal::test_closest tests/test_pyquery.py::TestTraversal::test_each tests/test_pyquery.py::TestTraversal::test_end tests/test_pyquery.py::TestTraversal::test_filter tests/test_pyquery.py::TestTraversal::test_find tests/test_pyquery.py::TestTraversal::test_is tests/test_pyquery.py::TestTraversal::test_map tests/test_pyquery.py::TestTraversal::test_next_all tests/test_pyquery.py::TestTraversal::test_next_until tests/test_pyquery.py::TestTraversal::test_not tests/test_pyquery.py::TestOpener::test_custom_opener tests/test_pyquery.py::TestOpener::test_invalid_filename tests/test_pyquery.py::TestOpener::test_open_filename tests/test_pyquery.py::TestConstruction::test_typeerror_on_invalid_value tests/test_pyquery.py::TestComment::test_comment tests/test_pyquery.py::TestCallback::test_S_this_inside_callback tests/test_pyquery.py::TestCallback::test_parameterless_callback tests/test_pyquery.py::TestHook::test_fn tests/test_pyquery.py::TestHook::test_fn_with_kwargs tests/test_pyquery.py::TestManipulating::test_attr_empty_string tests/test_pyquery.py::TestManipulating::test_class tests/test_pyquery.py::TestManipulating::test_html_replacement tests/test_pyquery.py::TestManipulating::test_remove tests/test_pyquery.py::TestManipulating::test_val_checkbox_no_value_attribute tests/test_pyquery.py::TestManipulating::test_val_for_input_and_textarea_given_array_value tests/test_pyquery.py::TestManipulating::test_val_for_inputs tests/test_pyquery.py::TestManipulating::test_val_for_inputs_with_newline tests/test_pyquery.py::TestManipulating::test_val_for_multiple_elements tests/test_pyquery.py::TestManipulating::test_val_for_select tests/test_pyquery.py::TestManipulating::test_val_for_select_multiple tests/test_pyquery.py::TestManipulating::test_val_input_has_no_value_attr tests/test_pyquery.py::TestManipulating::test_val_radio_no_value_attribute tests/test_pyquery.py::TestManipulating::test_val_value_is_empty_string tests/test_pyquery.py::TestAjax::test_serialize tests/test_pyquery.py::TestAjax::test_serialize_array tests/test_pyquery.py::TestAjax::test_serialize_dict tests/test_pyquery.py::TestAjax::test_serialize_pairs_filter_controls tests/test_pyquery.py::TestAjax::test_serialize_pairs_form_controls tests/test_pyquery.py::TestAjax::test_serialize_pairs_form_id tests/test_pyquery.py::TestAjax::test_serialize_pairs_form_values tests/test_pyquery.py::TestMakeLinks::test_make_link tests/test_pyquery.py::TestHTMLParser::test_parser_persistance tests/test_pyquery.py::TestHTMLParser::test_replaceWith tests/test_pyquery.py::TestHTMLParser::test_replaceWith_with_function tests/test_pyquery.py::TestXMLNamespace::test_namespace_traversal tests/test_pyquery.py::TestXMLNamespace::test_persistent_namespaces tests/test_pyquery.py::TestXMLNamespace::test_remove_namespaces tests/test_pyquery.py::TestXMLNamespace::test_selector tests/test_pyquery.py::TestXMLNamespace::test_selector_with_xml tests/test_pyquery.py::TestXMLNamespace::test_xhtml_namespace tests/test_pyquery.py::TestXMLNamespace::test_xhtml_namespace_html_parser tests/test_pyquery.py::TestWebScrapping::test_get tests/test_pyquery.py::TestWebScrapping::test_post tests/test_pyquery.py::TestWebScrapping::test_session tests/test_pyquery.py::TestWebScrappingEncoding::test_get tests/test_pyquery.py::TestWebScrappingTimeouts::test_get