Skip to content

Conversation

Maffooch
Copy link
Contributor

It is possible to set password reset for users that were authorized through SSO mechanisms. This has potential to lock a user into a flow of not being able to reset a password that does not exist

@Maffooch Maffooch requested a review from mtesauro as a code owner August 29, 2025 18:53
@github-actions github-actions bot added the apiv2 label Aug 29, 2025
Copy link

DryRun Security

This pull request contains two information disclosure vulnerabilities related to revealing SSO authentication details in error messages and help text, which could potentially provide attackers with insights into user authentication methods.

Information Disclosure in dojo/api_v2/serializers.py
Vulnerability Information Disclosure
Description The UserContactInfoSerializer in dojo/api_v2/serializers.py generates a specific validation error message, 'Password resets are not allowed for users authorized through SSO.', when a password reset is attempted for a user authenticated via SSO. This non-generic error message reveals an internal implementation detail (the user's authentication method), which can be leveraged by an attacker.

model = UserContactInfo
fields = "__all__"
def validate(self, data):
user = data.get("user", None) or self.instance.user
if data.get("force_password_reset", False) and not user.has_usable_password():
msg = "Password resets are not allowed for users authorized through SSO."
raise ValidationError(msg)
return super().validate(data)
class UserStubSerializer(serializers.ModelSerializer):
class Meta:

Information Disclosure in dojo/forms.py
Vulnerability Information Disclosure
Description The UserContactInfoForm displays a help text message indicating if a user is authorized through SSO. This information is disclosed to any user with auth.change_user permission when they access the edit_user page for another user. While this permission is typically for administrators, the authentication method of a user can be considered sensitive information that should not be unnecessarily exposed.

exclude = ["user", "slack_user_id"]
def __init__(self, *args, **kwargs):
user = kwargs.pop("user", None)
super().__init__(*args, **kwargs)
# Do not expose force password reset if the current user does not have a password to reset
if user is not None:
if not user.has_usable_password():
self.fields["force_password_reset"].disabled = True
self.fields["force_password_reset"].help_text = "This user is authorized through SSO, and does not have a password to reset"
# Determine some other settings based on the current user
current_user = get_current_user()
if not current_user.is_superuser:
if not user_has_configuration_permission(current_user, "auth.change_user") and \


All finding details can be found in the DryRun Security Dashboard.

@valentijnscholten valentijnscholten added this to the 2.50.0 milestone Aug 30, 2025
Copy link
Contributor

@mtesauro mtesauro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@valentijnscholten valentijnscholten modified the milestones: 2.50.0, 2.51.0, 2.50.1 Sep 2, 2025
@valentijnscholten valentijnscholten merged commit a653695 into bugfix Sep 2, 2025
87 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants