diff --git a/reviewboard/reviews/markdown_utils.py b/reviewboard/reviews/markdown_utils.py
index 7cb01ef0f4480540f4b2ab1b57a7835c489e4280..fee70e00dffd8bfa7275ef86137ae0b84599b1a3 100644
--- a/reviewboard/reviews/markdown_utils.py
+++ b/reviewboard/reviews/markdown_utils.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 import re
+import sys
 from xml.dom.minidom import parseString
 
 from django.core.exceptions import ObjectDoesNotExist
@@ -77,6 +78,8 @@ MARKDOWN_KWARGS = {
     },
 }
 
+ILLEGAL_XML_CHARS_RE = None
+
 
 def markdown_escape(text):
     """Escapes text for use in Markdown.
@@ -258,10 +261,47 @@ def get_markdown_element_tree(markdown_html):
     if isinstance(markdown_html, six.text_type):
         markdown_html = markdown_html.encode('utf-8')
 
+    markdown_html = sanitize_illegal_chars_for_xml(markdown_html)
+
     doc = parseString(b'<html>%s</html>' % markdown_html)
     return doc.childNodes[0].childNodes
 
 
+def sanitize_illegal_chars_for_xml(s):
+    """Sanitize a string, removing characters illegal in XML.
+
+    This will remove a number of characters that would break the  XML parser.
+    They may be in the string due to a copy/paste.
+
+    This code is courtesy of the XmlRpcPlugin developers, as documented
+    here: http://stackoverflow.com/a/22273639
+    """
+    global ILLEGAL_XML_CHARS_RE
+
+    if ILLEGAL_XML_CHARS_RE is None:
+        _illegal_unichrs = [
+            (0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84),
+            (0x86, 0x9F), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF)
+        ]
+
+        if sys.maxunicode > 0x10000:
+            _illegal_unichrs += [
+                (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF),
+                (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
+                (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF),
+                (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
+                (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF),
+                (0x10FFFE, 0x10FFFF)
+            ]
+
+        ILLEGAL_XML_CHARS_RE = re.compile('[%s]' % ''.join([
+            '%s-%s' % (unichr(low), unichr(high))
+            for low, high in _illegal_unichrs
+        ]))
+
+    return ILLEGAL_XML_CHARS_RE.sub('', s)
+
+
 def render_markdown(text):
     """Renders Markdown text to HTML.
 
diff --git a/reviewboard/reviews/tests.py b/reviewboard/reviews/tests.py
index 4b5878c9b7423008654f896daee5abfe11933998..7a350ccf56608441ce6ab55e23fb832d92d453a0 100644
--- a/reviewboard/reviews/tests.py
+++ b/reviewboard/reviews/tests.py
@@ -18,7 +18,8 @@ from kgb import SpyAgency
 from reviewboard.accounts.models import Profile, LocalSiteProfile
 from reviewboard.attachments.models import FileAttachment
 from reviewboard.reviews.forms import DefaultReviewerForm, GroupForm
-from reviewboard.reviews.markdown_utils import (markdown_escape,
+from reviewboard.reviews.markdown_utils import (get_markdown_element_tree,
+                                                markdown_escape,
                                                 markdown_unescape,
                                                 normalize_text_for_edit,
                                                 render_markdown)
@@ -2705,6 +2706,20 @@ class MarkdownUtilsTests(TestCase):
     UNESCAPED_TEXT = r'\`*_{}[]()#+-.!'
     ESCAPED_TEXT = r'\\\`\*\_\{\}\[\]\(\)#+-.\!'
 
+    def test_get_markdown_element_tree(self):
+        """Testing get_markdown_element_tree"""
+        node = get_markdown_element_tree(render_markdown('**Test**\nHi.'))
+
+        self.assertEqual(node[0].toxml(),
+                         '<p><strong>Test</strong><br/>\n'
+                         'Hi.</p>')
+
+    def test_get_markdown_element_tree_with_illegal_chars(self):
+        """Testing get_markdown_element_tree with illegal characters"""
+        node = get_markdown_element_tree(render_markdown('(**Test**\x0C)'))
+
+        self.assertEqual(node[0].toxml(), '<p>(<strong>Test</strong>)</p>')
+
     def test_markdown_escape(self):
         """Testing markdown_escape"""
         self.assertEqual(markdown_escape(self.UNESCAPED_TEXT),
