[Django] #37184: PBKDF2PasswordHasher no longer accepts password of type bytes

0 views
Skip to first unread message

Django

unread,
Jun 23, 2026, 5:22:44 PM (19 hours ago) Jun 23
to django-...@googlegroups.com
#37184: PBKDF2PasswordHasher no longer accepts password of type bytes
-------------------------------------+-------------------------------------
Reporter: Johannes Leuschner | Type: Bug
Status: new | Component:
| contrib.auth
Version: 6.0 | Severity: Normal
Keywords: PBKDF2 hasher | Triage Stage:
password bytes UTF-8 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Before 78fac1b0473ed8960ecd2a30aca4fa8420d150b8, `PBKDF2PasswordHasher`
(which is the default hasher) used to accept a password of type `bytes` in
`make_password` and `check_password`. After that commit, `force_str` is
called on the password, raising a decoding error if the bytes are not
valid UTF-8. The
[https://github.com/django/django/blob/d01aaa5b1c8b89aedbcd9fbed497e4c69c72d0b1/django/utils/crypto.py#L86
pbkdf2 implementation] then actually converts back to `bytes`.

Minimal example:

{{{
from django.contrib.auth.hashers import make_password
make_password(b"\xc0", hasher="pbkdf2_sha256") # fails with
DjangoUnicodeDecodeError
}}}

and also

{{{
from django.contrib.auth.hashers import make_password, check_password
encoded = make_password(b"", hasher="pbkdf2_sha256")
check_password(b"\xc0", encoded) # fails with DjangoUnicodeDecodeError
}}}

A use-case for passing a password of type `bytes` is generated
passwords/keys, which can be exposed to the user e.g. via base64 encoding.
This maximizes password strength compared to only allowing valid UTF-8
characters, and generating random passwords with a restricted character
set is not as straight-forward. Existing applications using passwords of
type `bytes` now fail both at making and checking passwords.

Note that in the same commit `force_str` is also introduced to
`MD5PasswordHasher`, but there it makes sense because `.encode()` has been
called anyways, i.e. `bytes` was not supported before.
--
Ticket URL: <https://code.djangoproject.com/ticket/37184>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jun 23, 2026, 7:17:33 PM (17 hours ago) Jun 23
to django-...@googlegroups.com
#37184: PBKDF2PasswordHasher no longer accepts password of type bytes
-------------------------------------+-------------------------------------
Reporter: Johannes Leuschner | Owner: (none)
Type: Bug | Status: new
Component: contrib.auth | Version: 6.0
Severity: Normal | Resolution:
Keywords: PBKDF2 hasher | Triage Stage:
password bytes UTF-8 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mike Edmunds):

The
[https://docs.djangoproject.com/en/6.1/topics/auth/passwords/#django.contrib.auth.hashers.make_password:~:text=the%20password%20in%20plain%2Dtext%20(string%20or%20bytes)
make_password() docs] are a little confusing (or at least open to
interpretation):

> … It takes one mandatory argument: the password in plain-text (string or
bytes). …

It looks like "plain-text … bytes" is really trying to say "utf-8 encoded
text." If so, then `b"\xc0"` is not a valid "plain-text bytes" password
and the error is correct. And this should be treated as a docs
clarification bug (for both `make_password()` and `check_password()`).

But if "plain-text … bytes" actually means "a text password in the app's
choice of encoding," then this is/was a breaking change. (And that's
unclear to me: the password hashers have bounced back and forth between
`force_bytes()` and `encode()` over time: see #36226 and #27795. During
the `force_bytes()` periods, I think any encoding would have been
acceptable so long as it was consistently applied.)
--
Ticket URL: <https://code.djangoproject.com/ticket/37184#comment:1>

Django

unread,
7:45 AM (4 hours ago) 7:45 AM
to django-...@googlegroups.com
#37184: PBKDF2PasswordHasher no longer accepts password of type bytes
-------------------------------------+-------------------------------------
Reporter: Johannes Leuschner | Owner: Vishy
Type: Bug | Status: assigned
Component: contrib.auth | Version: 6.0
Severity: Normal | Resolution:
Keywords: PBKDF2 hasher | Triage Stage:
password bytes UTF-8 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Vishy):

* owner: (none) => Vishy
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/37184#comment:2>
Reply all
Reply to author
Forward
0 new messages