Skip to content

Commit 660015a

Browse files
committed
When we generate links from URL's in messages, we add rel="nofollow"
to combat link spam. This change turns that into rel="nofollow noopener". This prevents the page at the end of the link from having access to the roundup window that displays the link. Details on the issue are are at: https://mathiasbynens.github.io/rel-noopener/ search web for noopener vulnerability. This problem usually requires a target="_blank" to really exploit it and we don't provide that. But adding noopener is extra protection.
1 parent 4c02f7f commit 660015a

File tree

3 files changed

+20
-17
lines changed

3 files changed

+20
-17
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ Fixed:
112112
- issue2551026: template variable not defined even though it is.
113113
Fix issue where variables defined in TAL expression are not
114114
available in the scope of the definition. (Tom Ekberg (tekberg))
115+
- Make all links created with rel=nofollow include noopener. Deals
116+
with possible hijack of original page due to malicious link target.
117+
https://mathiasbynens.github.io/rel-noopener/ (John Rouillard)
115118

116119
2018-07-13 1.6.0
117120

roundup/cgi/templating.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ def history(self, direction='descending', dre=re.compile('^\d+$'),
957957
if action in ['link', 'unlink'] and type(args) == type(()):
958958
if len(args) == 3:
959959
linkcl, linkid, key = args
960-
arg_s += '<a rel="nofollow" href="%s%s">%s%s %s</a>'%(linkcl, linkid,
960+
arg_s += '<a rel="nofollow noopener" href="%s%s">%s%s %s</a>'%(linkcl, linkid,
961961
linkcl, linkid, key)
962962
else:
963963
arg_s = str(args)
@@ -997,7 +997,7 @@ def history(self, direction='descending', dre=re.compile('^\d+$'),
997997
pass
998998
else:
999999
linkid = self._klass.get(self._nodeid, k, None)
1000-
current[k] = '<a rel="nofollow" href="%s%s">%s</a>'%(
1000+
current[k] = '<a rel="nofollow noopener" href="%s%s">%s</a>'%(
10011001
classname, linkid, current[k])
10021002

10031003
if args[k] and (isinstance(prop, hyperdb.Multilink) or
@@ -1052,7 +1052,7 @@ def history(self, direction='descending', dre=re.compile('^\d+$'),
10521052
subml.append('<strike>%s</strike>'%label)
10531053
else:
10541054
if hrefable:
1055-
subml.append('<a rel="nofollow" '
1055+
subml.append('<a rel="nofollow noopener" '
10561056
'href="%s%s">%s</a>'%(
10571057
classname, linkid, label))
10581058
elif label is None:
@@ -1080,7 +1080,7 @@ def history(self, direction='descending', dre=re.compile('^\d+$'),
10801080
label = None
10811081
if label is not None:
10821082
if hrefable:
1083-
old = '<a ref="nofollow" href="%s%s">%s</a>'%(classname,
1083+
old = '<a ref="nofollow noopener" href="%s%s">%s</a>'%(classname,
10841084
args[k], label)
10851085
else:
10861086
old = label;
@@ -1407,7 +1407,7 @@ class StringHTMLProperty(HTMLProperty):
14071407

14081408
def _hyper_repl(self, match):
14091409
if match.group('url'):
1410-
return self._hyper_repl_url(match, '<a href="%s" rel="nofollow">%s</a>%s')
1410+
return self._hyper_repl_url(match, '<a href="%s" rel="nofollow noopener">%s</a>%s')
14111411
elif match.group('email'):
14121412
return self._hyper_repl_email(match, '<a href="mailto:%s">%s</a>')
14131413
elif len(match.group('id')) < 10:

test/test_templating.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -264,37 +264,37 @@ def t(s): return p.hyper_re.sub(p._hyper_repl, s)
264264
ae = self.assertEqual
265265
ae(t('item123123123123'), 'item123123123123')
266266
ae(t('http://roundup.net/'),
267-
'<a href="http://roundup.net/" rel="nofollow">http://roundup.net/</a>')
267+
'<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>')
268268
ae(t('&lt;HTTP://roundup.net/&gt;'),
269-
'&lt;<a href="HTTP://roundup.net/" rel="nofollow">HTTP://roundup.net/</a>&gt;')
269+
'&lt;<a href="HTTP://roundup.net/" rel="nofollow noopener">HTTP://roundup.net/</a>&gt;')
270270
ae(t('&lt;http://roundup.net/&gt;.'),
271-
'&lt;<a href="http://roundup.net/" rel="nofollow">http://roundup.net/</a>&gt;.')
271+
'&lt;<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>&gt;.')
272272
ae(t('&lt;www.roundup.net&gt;'),
273-
'&lt;<a href="http://www.roundup.net" rel="nofollow">www.roundup.net</a>&gt;')
273+
'&lt;<a href="http://www.roundup.net" rel="nofollow noopener">www.roundup.net</a>&gt;')
274274
ae(t('(www.roundup.net)'),
275-
'(<a href="http://www.roundup.net" rel="nofollow">www.roundup.net</a>)')
275+
'(<a href="http://www.roundup.net" rel="nofollow noopener">www.roundup.net</a>)')
276276
ae(t('foo http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx bar'),
277-
'foo <a href="http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx" rel="nofollow">'
277+
'foo <a href="http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx" rel="nofollow noopener">'
278278
'http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx</a> bar')
279279
ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))'),
280-
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow">'
280+
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
281281
'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)')
282282
ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language)).'),
283-
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow">'
283+
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
284284
'http://en.wikipedia.org/wiki/Python_(programming_language)</a>).')
285285
ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))&gt;.'),
286-
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow">'
286+
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
287287
'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)&gt;.')
288288
ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language&gt;)).'),
289-
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language" rel="nofollow">'
289+
'(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language" rel="nofollow noopener">'
290290
'http://en.wikipedia.org/wiki/Python_(programming_language</a>&gt;)).')
291291
for c in '.,;:!':
292292
# trailing punctuation is not included
293293
ae(t('http://roundup.net/%c ' % c),
294-
'<a href="http://roundup.net/" rel="nofollow">http://roundup.net/</a>%c ' % c)
294+
'<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>%c ' % c)
295295
# but it's included if it's part of the URL
296296
ae(t('http://roundup.net/%c/' % c),
297-
'<a href="http://roundup.net/%c/" rel="nofollow">http://roundup.net/%c/</a>' % (c, c))
297+
'<a href="http://roundup.net/%c/" rel="nofollow noopener">http://roundup.net/%c/</a>' % (c, c))
298298

299299
'''
300300
class HTMLPermissions:

0 commit comments

Comments
 (0)