CVE-2020-5224: Inadequate Encryption Strength (CWE-326)
value: In Django User Sessions (django-user-sessions) before 1.7.1, the views provided allow users to terminate specific sessions. The session key is used to identify sessions, and thus included in the rendered HTML. In itself this is not a problem. However if the website has an XSS vulnerability, the session key could be extracted by the attacker and a session takeover could happen.
CWE description: The product stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.
CVSS v3 base score: 8.8
Published: 2020-01-24T20:15Z
Repository: https://github.com/jazzband/django-user-sessions
Language: Python
Files changed: tests/tests.py, user_sessions/templates/user_sessions/session_list.html
Commit date: 2020-01-24 15:14:29 +0100
Commit message: Don't expose session keys in views

Diff: diff --git a/tests/tests.py b/tests/tests.py
index 650fd65..68efef0 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -86,12 +86,12 @@ class ViewsTest(TestCase):
         self.user.session_set.create(session_key='ABC123', ip='127.0.0.1',
                                      expire_date=datetime.now() + timedelta(days=1),
                                      user_agent='Firefox')
         response = self.client.get(reverse('user_sessions:session_list'))
         self.assertContains(response, 'Active Sessions')
-        self.assertContains(response, 'End Session', 3)
         self.assertContains(response, 'Firefox')
+        self.assertNotContains(response, 'ABC123')
 
     def test_delete(self):
         session_key = self.client.cookies[settings.SESSION_COOKIE_NAME].value
         response = self.client.post(reverse('user_sessions:session_delete',
                                             args=[session_key]))
diff --git a/user_sessions/templates/user_sessions/session_list.html b/user_sessions/templates/user_sessions/session_list.html
index e7ea361..0e872b4 100644
--- a/user_sessions/templates/user_sessions/session_list.html
+++ b/user_sessions/templates/user_sessions/session_list.html
@@ -11,11 +11,10 @@
     <thead>
       <tr>
         <th>{% trans "Location" %}</th>
         <th>{% trans "Device" %}</th>
         <th>{% trans "Last Activity" %}</th>
-        <th>{% trans "End Session" %}</th>
       </tr>
     </thead>
     {% for object in object_list %}
       <tr {% if object.session_key == session_key %}class="active"{% endif %}>
         <td>{{ object.ip|location|default_if_none:unknown|safe }} <small>({{ object.ip }})</small></td>
@@ -25,20 +24,10 @@
             {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago (this session){% endblocktrans %}
           {% else %}
             {% blocktrans with time=object.last_activity|timesince %}{{ time }} ago{% endblocktrans %}
           {% endif %}
         </td>
-        <td>
-          <form method="post" action="{% url 'user_sessions:session_delete' object.pk %}">
-            {% csrf_token %}
-            {% if object.session_key == session_key %}
-              <button type="submit" class="btn btn-xs btn-link">{% trans "End Session" %}</button>
-            {% else %}
-              <button type="submit" class="btn btn-xs btn-warning">{% trans "End Session" %}</button>
-            {% endif %}
-          </form>
-        </td>
       </tr>
     {% endfor %}
   </table>
 
   {% if object_list.count > 1 %}

Vulnerable code:         self.assertContains(response, 'End Session', 3)
        <th>{% trans "End Session" %}</th>
        <td>
          <form method="post" action="{% url 'user_sessions:session_delete' object.pk %}">
            {% csrf_token %}
            {% if object.session_key == session_key %}
              <button type="submit" class="btn btn-xs btn-link">{% trans "End Session" %}</button>
            {% else %}
              <button type="submit" class="btn btn-xs btn-warning">{% trans "End Session" %}</button>
            {% endif %}
          </form>
        </td>
Fixed code:         self.assertNotContains(response, 'ABC123')