Opened 70 minutes ago

Last modified 16 minutes ago

#37078 new Cleanup/optimization

salted_hmac() defaults to SHA-1 algorithm despite SHA-256 being preferred everywhere else

Reported by: Denny Biasiolli Owned by:
Component: Utilities Version:
Severity: Normal Keywords: security, crypto
Cc: Denny Biasiolli Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

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).

Change History (3)

comment:1 by Denny Biasiolli, 65 minutes ago

Has patch: set

comment:2 by Tim Graham, 25 minutes ago

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.

comment:3 by Jacob Walls, 16 minutes ago

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?)

Note: See TracTickets for help on using tickets.
Back to Top