Skip to content
Browse files

Fixed CVE-2018-16984 -- Fixed password hash disclosure to admin "view…

… only" users.

Thanks Claude Paroz & Tim Graham for collaborating on the patch.

# Conflicts:
#	tests/auth_tests/
  • Loading branch information
carltongibson committed Sep 13, 2018
1 parent f86100a commit c4bd5b597e0aa2432e4c867b86650f18af117851
Showing with 44 additions and 3 deletions.
  1. +6 −0 django/contrib/admin/
  2. +1 −0 django/contrib/auth/
  3. +11 −2 docs/releases/2.1.2.txt
  4. +26 −1 tests/auth_tests/
@@ -202,6 +202,12 @@ def contents(self):
except (AttributeError, ValueError, ObjectDoesNotExist):
result_repr = self.empty_value_display
if field in self.form.fields:
widget = self.form[field].field.widget
# This isn't elegant but suffices for contrib.auth's
# ReadOnlyPasswordHashWidget.
if getattr(widget, 'read_only', False):
return widget.render(field, value)
if f is None:
if getattr(attr, 'boolean', False):
result_repr = _boolean_icon(value)
@@ -22,6 +22,7 @@

class ReadOnlyPasswordHashWidget(forms.Widget):
template_name = 'auth/widgets/read_only_password_hash.html'
read_only = True

def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
@@ -4,8 +4,17 @@ Django 2.1.2 release notes

*Expected October 1, 2018*

Django 2.1.2 fixes several bugs in 2.1.1. Also, the latest string translations
from Transifex are incorporated.
Django 2.1.2 fixes a security issue and several bugs in 2.1.1. Also, the latest
string translations from Transifex are incorporated.

CVE-2018-16984: Password hash disclosure to "view only" admin users

If an admin user has the change permission to the user model, only part of the
password hash is displayed in the change form. Admin users with the view (but
not change) permission to the user model were displayed the entire hash. While
it's typically infeasible to reverse a strong password hash, if your site uses
weaker password hashing algorithms such as MD5 or SHA1, it could be a problem.

@@ -14,11 +14,12 @@
from django.contrib.auth.forms import (
AuthenticationForm, PasswordChangeForm, SetPasswordForm,
from django.contrib.auth.models import User
from django.contrib.auth.models import Permission, User
from django.contrib.auth.views import (
INTERNAL_RESET_SESSION_TOKEN, LoginView, logout_then_login,
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sites.requests import RequestSite
from django.core import mail
@@ -1115,6 +1116,11 @@ def test_logout_redirect_url_named_setting(self):
self.assertRedirects(response, '/logout/', fetch_redirect_response=False)

def get_perm(Model, perm):
ct = ContentType.objects.get_for_model(Model)
return Permission.objects.get(content_type=ct, codename=perm)

# Redirect in test_user_change_password will fail if session auth hash
# isn't updated after password change (#21649)
@@ -1221,6 +1227,25 @@ def test_password_change_bad_url(self):
response = self.client.get(reverse('auth_test_admin:auth_user_password_change', args=('foobar',)))
self.assertEqual(response.status_code, 404)

def test_view_user_password_is_readonly(self):
u = User.objects.get(username='testclient')
u.is_superuser = False
u.user_permissions.add(get_perm(User, 'view_user'))
response = self.client.get(reverse('auth_test_admin:auth_user_change', args=(,)),)
algo, salt, hash_string = (u.password.split('$'))
self.assertContains(response, '<div class="readonly">testclient</div>')
# ReadOnlyPasswordHashWidget is used to render the field.
'<strong>algorithm</strong>: %s\n\n'
'<strong>salt</strong>: %s**********\n\n'
'<strong>hash</strong>: %s**************************\n\n' % (
algo, salt[:2], hash_string[:6],


0 comments on commit c4bd5b5

Please sign in to comment.
You can’t perform that action at this time.