[Django] #37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred everywhere else

4 views
Skip to first unread message

Django

unread,
Apr 29, 2026, 1:00:12 PM (yesterday) Apr 29
to django-...@googlegroups.com
#37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred
everywhere else
-------------------------------------+-------------------------------------
Reporter: Denny Biasiolli | Type:
| Cleanup/optimization
Status: new | Component: Utilities
Version: | Severity: Normal
Keywords: security, crypto | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
The `salted_hmac()` function (`crypto.py:19`) defaults to
`algorithm="sha1"`. While HMAC-SHA1 is not cryptographically broken (HMAC
construction is resistant to collision attacks), SHA-1 is deprecated by
NIST and modern security standards recommend SHA-256 or stronger for all
new applications.

All security-sensitive callers within Django already override this default
— `Signer` uses `sha256` (signing.py:193), `PasswordResetTokenGenerator`
passes `sha256` explicitly, and session auth hashes use SHA-256. However,
any third-party code or custom application calling `salted_hmac()` without
specifying an algorithm will silently use SHA-1.

## Steps to Reproduce

1. In any Django project, call:
```python
from django.utils.crypto import salted_hmac
mac = salted_hmac("my_salt", "my_value")
print(mac.digest_size) # 20 bytes = SHA-1
```
2. Observe the HMAC uses SHA-1 without any explicit algorithm selection

## Expected Behavior

`salted_hmac()` should default to `"sha256"` to match modern cryptographic
best practices and align with Django's own internal usage.

## Actual Behavior

`salted_hmac()` defaults to `algorithm="sha1"` (line 19 of `crypto.py`).
--
Ticket URL: <https://code.djangoproject.com/ticket/37078>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 29, 2026, 1:05:50 PM (yesterday) Apr 29
to django-...@googlegroups.com
#37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred
everywhere else
-------------------------------------+-------------------------------------
Reporter: Denny Biasiolli | Owner: (none)
Type: | Status: new
Cleanup/optimization |
Component: Utilities | Version:
Severity: Normal | Resolution:
Keywords: security, crypto | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Denny Biasiolli):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/37078#comment:1>

Django

unread,
Apr 29, 2026, 1:45:12 PM (yesterday) Apr 29
to django-...@googlegroups.com
#37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred
everywhere else
-------------------------------------+-------------------------------------
Reporter: Denny Biasiolli | Owner: (none)
Type: | Status: new
Cleanup/optimization |
Component: Utilities | Version:
Severity: Normal | Resolution:
Keywords: security, crypto | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Tim Graham):

Previous work was done in #27468. We cannot just change default value of
the parameter due to backward compatibility. The change would have to go
through a deprecation.
--
Ticket URL: <https://code.djangoproject.com/ticket/37078#comment:2>

Django

unread,
Apr 29, 2026, 1:55:01 PM (yesterday) Apr 29
to django-...@googlegroups.com
#37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred
everywhere else
-------------------------------------+-------------------------------------
Reporter: Denny Biasiolli | Owner: (none)
Type: | Status: new
Cleanup/optimization |
Component: Utilities | Version:
Severity: Normal | Resolution:
Keywords: security, crypto | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls):

A deprecation might make sense, but just to check my understanding -- Tim,
does it make a difference that `base64_hmac()` isn't documented? (And that
all uses in Django have already migrated?)
--
Ticket URL: <https://code.djangoproject.com/ticket/37078#comment:3>

Django

unread,
9:39 AM (12 hours ago) 9:39 AM
to django-...@googlegroups.com
#37078: salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred
everywhere else
-------------------------------------+-------------------------------------
Reporter: Denny Biasiolli | Owner: (none)
Type: | Status: new
Cleanup/optimization |
Component: Utilities | Version:
Severity: Normal | Resolution:
Keywords: security, crypto | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* has_patch: 1 => 0

Comment:

There's at least one usage of `base64_hmac()` in
[https://github.com/search?q=%22django.core.signing+import+base64_hmac%22+language%3APython&type=code&p=1
healthchecks]. Even if undocumented, I wouldn't modify security-related
functionality lightly.
--
Ticket URL: <https://code.djangoproject.com/ticket/37078#comment:4>
Reply all
Reply to author
Forward
0 new messages