python.django.security.audit.unvalidated-password.unvalidated-password
Community Favorite
semgrep
Author
48,153
Download Count*
License
The password on '$MODEL' is being set without validating the password. Call django.contrib.auth.password_validation.validate_password() with validation functions before setting the password. See https://docs.djangoproject.com/en/3.0/topics/auth/passwords/ for more information.
Run Locally
Run in CI
Defintion
rules:
- id: unvalidated-password
patterns:
- pattern-not-inside: >
if <... django.contrib.auth.password_validation.validate_password(...)
...>:
...
- pattern-not-inside: |
django.contrib.auth.password_validation.validate_password(...)
...
- pattern-not-inside: |
try:
...
django.contrib.auth.password_validation.validate_password(...)
...
except $EX:
...
...
- pattern-not-inside: |
try:
...
django.contrib.auth.password_validation.validate_password(...)
...
except $EX as $E:
...
...
- pattern-not: UserModel().set_password($X)
- pattern: $MODEL.set_password($X)
fix: >
if django.contrib.auth.password_validation.validate_password($X,
user=$MODEL):
$MODEL.set_password($X)
message: The password on '$MODEL' is being set without validating the password.
Call django.contrib.auth.password_validation.validate_password() with
validation functions before setting the password. See
https://docs.djangoproject.com/en/3.0/topics/auth/passwords/ for more
information.
metadata:
cwe:
- "CWE-521: Weak Password Requirements"
owasp:
- A07:2021 - Identification and Authentication Failures
references:
- https://docs.djangoproject.com/en/3.0/topics/auth/passwords/#module-django.contrib.auth.password_validation
category: security
technology:
- django
subcategory:
- audit
likelihood: LOW
impact: MEDIUM
confidence: LOW
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Improper Authentication
languages:
- python
severity: WARNING
Examples
unvalidated-password.py
import os
import ujson
from typing import Any, Dict, List
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
from django.shortcuts import render
from django.test import Client
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from tests import example_user
from models import UserProfile
from backend import EmailAuthBackend
from somewhere import BaseBackend
from django.contrib.auth import get_user_model
UserModel = get_user_model()
def test_email_auth_backend_empty_password(user_profile: UserProfile) -> None:
user_profile = example_user('hamlet')
password = "testpassword"
try:
validate_password(password)
except ValidationError as e:
return HttpResponseBadRequest(str(e))
# ok: unvalidated-password
user_profile.set_password(password)
user_profile.save()
user_profile.assertIsNotNone(EmailAuthBackend().authenticate(username=user_profile.example_email('hamlet'), password=password))
def other(user_profile: UserProfile) -> None:
user_profile = example_user('hamlet')
password = "testpassword"
# ruleid: unvalidated-password
user_profile.set_password(password)
user_profile.save()
user_profile.assertIsNotNone(EmailAuthBackend().authenticate(username=user_profile.example_email('hamlet'), password=password))
class ModelBackend(BaseBackend):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
# ok: unvalidated-password
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
Short Link: https://sg.run/OPBL