Skip to content

Commit 77ac646

Browse files
committed
Fix a XSS vulnerability in the gravatar template tag.
The generated gravatar HTML wasn't handling escaping of the display name of the user, allowing an attacker to choose a name that would close out the <img> tag and inject a <script> tag. By switching to Django's format_html(), we can guarantee safe escaping of content.
1 parent 77a68c0 commit 77ac646

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

Diff for: djblets/gravatars/templatetags/gravatars.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from __future__ import unicode_literals
2626

2727
from django import template
28+
from django.utils.html import format_html
2829

2930
from djblets.gravatars import (get_gravatar_url,
3031
get_gravatar_url_for_email)
@@ -55,9 +56,10 @@ def gravatar(context, user, size=None):
5556
url = get_gravatar_url(context['request'], user, size)
5657

5758
if url:
58-
return ('<img src="%s" width="%s" height="%s" alt="%s" '
59-
' class="gravatar"/>' %
60-
(url, size, size, user.get_full_name() or user.username))
59+
return format_html(
60+
'<img src="{0}" width="{1}" height="{1}" alt="{2}" '
61+
'class="gravatar"/>',
62+
url, size, user.get_full_name() or user.username)
6163
else:
6264
return ''
6365

Diff for: djblets/gravatars/templatetags/tests.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from __future__ import unicode_literals
2+
3+
from django.contrib.auth.models import User
4+
from django.template import Token, TOKEN_TEXT
5+
6+
from djblets.testing.testcases import TagTest
7+
from djblets.gravatars.templatetags.gravatars import gravatar
8+
9+
10+
class DummyRequest(object):
11+
def is_secure(self):
12+
return False
13+
14+
15+
class TagTests(TagTest):
16+
"""Unit tests for gravatars template tags."""
17+
def test_gravatar_xss(self):
18+
"""Testing {% gravatar %} doesn't allow XSS injection"""
19+
user = User(username='test',
20+
first_name='"><script>alert(1);</script><"',
21+
email='test@example.com')
22+
23+
node = gravatar(self.parser, Token(TOKEN_TEXT, 'gravatar user 32'))
24+
context = {
25+
'request': DummyRequest(),
26+
'user': user,
27+
}
28+
29+
self.assertEqual(
30+
node.render(context),
31+
'<img src="http://www.gravatar.com/avatar/'
32+
'55502f40dc8b7c769880b10874abc9d0?s=32" width="32" height="32" '
33+
'alt="&quot;&gt;&lt;script&gt;alert(1);&lt;/script&gt;&lt;&quot;" '
34+
'class="gravatar"/>')

0 commit comments

Comments
 (0)