diff --git a/bodhi/server/util.py b/bodhi/server/util.py
index cc86afc086..0b802085b3 100644
--- a/bodhi/server/util.py
+++ b/bodhi/server/util.py
@@ -563,8 +563,9 @@ def bug_link(context, bug, short=False):
link = "%s" % (url, display)
if not short:
if bug.title:
- # We're good...
- link = link + " " + bug.title
+ # We're good, but we do need to clean the bug title in case it contains malicious
+ # tags. See CVE-2017-1002152: https://github.com/fedora-infra/bodhi/issues/1740
+ link = link + " " + bleach.clean(bug.title, tags=[], attributes=[])
else:
# Otherwise, the backend is async grabbing the title from rhbz, so
link = link + " "
diff --git a/bodhi/tests/server/test_utils.py b/bodhi/tests/server/test_utils.py
index 5d7bdae002..e754f0f219 100644
--- a/bodhi/tests/server/test_utils.py
+++ b/bodhi/tests/server/test_utils.py
@@ -42,6 +42,38 @@ def test_short_false_with_title(self):
(""
"#1234567 Lucky bug number"))
+ def test_short_false_with_title_sanitizes_safe_tags(self):
+ """
+ Test that a call to bug_link() with short=False on a Bug that has a title sanitizes even
+ safe tags because really they should be rendered human readable.
+ """
+ bug = mock.MagicMock()
+ bug.bug_id = 1234567
+ bug.title = 'Check this out'
+
+ link = util.bug_link(None, bug)
+
+ self.assertEqual(
+ link,
+ (""
+ "#1234567 Check <b>this</b> out"))
+
+ def test_short_false_with_title_sanitizes_unsafe_tags(self):
+ """
+ Test that a call to bug_link() with short=False on a Bug that has a title sanitizes unsafe
+ tags.
+ """
+ bug = mock.MagicMock()
+ bug.bug_id = 1473091
+ bug.title = ' should be optional'
+
+ link = util.bug_link(None, bug)
+
+ self.assertEqual(
+ link,
+ (""
+ "#1473091 <disk> <driver name=\"...\"> should be optional"))
+
def test_short_false_without_title(self):
"""Test a call to bug_link() with short=False on a Bug that has no title."""
bug = mock.MagicMock()
diff --git a/docs/conf.py b/docs/conf.py
index f72c706398..6276604691 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -53,7 +53,7 @@
# The short X.Y version.
version = '2.9'
# The full version, including alpha/beta/rc tags.
-release = '2.9.0'
+release = '2.9.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/release_notes.rst b/docs/release_notes.rst
index b8c9522f21..342586e5fe 100644
--- a/docs/release_notes.rst
+++ b/docs/release_notes.rst
@@ -1,6 +1,18 @@
Release notes
=============
+2.9.1
+-----
+
+2.9.1 is a security release for
+`CVE-2017-1002152 `_.
+
+Release contributors
+^^^^^^^^^^^^^^^^^^^^
+
+Thanks to Marcel for reporting the issue. Randy Barlow wrote the fix.
+
+
2.9.0
-----
diff --git a/setup.py b/setup.py
index ba739ed81a..13b48766b6 100644
--- a/setup.py
+++ b/setup.py
@@ -46,7 +46,7 @@ def get_requirements(requirements_file='requirements.txt'):
here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.rst')).read()
-VERSION = '2.9.0'
+VERSION = '2.9.1'
# Possible options are at https://pypi.python.org/pypi?%3Aaction=list_classifiers
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',