VYPR
Low severity2.7NVD Advisory· Published Mar 31, 2026· Updated Apr 7, 2026

CVE-2026-34203

CVE-2026-34203

Description

Nautobot is a Network Source of Truth and Network Automation Platform. Prior to versions 2.4.30 and 3.0.10, user creation and editing via the REST API fails to apply the password validation rules defined by Django's AUTH_PASSWORD_VALIDATORS setting (which defaults to an empty list, i.e., no specific rules, but can be configured in Nautobot's nautobot_config.py to apply various rules if desired). This can potentially allow for the creation or modification of users to have passwords that are weak or otherwise do not comply with configured standards. This issue has been patched in versions 2.4.30 and 3.0.10.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
nautobotPyPI
< 2.4.302.4.30
nautobotPyPI
>= 3.0.0, < 3.0.103.0.10

Affected products

1

Patches

2
d1ef3135aa02

[3.0] Add call to validate_password when managing users via REST API (#8778)

https://github.com/nautobot/nautobotGlenn MatthewsMar 30, 2026via ghsa
5 files changed · +89 0
  • changes/8778.security+1 0 added
    @@ -0,0 +1 @@
    +Added missing enforcement of any configured Django password validators when managing users via the REST API (CVE-2026-34203).
    
  • nautobot/core/settings.yaml+14 0 modified
    @@ -113,6 +113,20 @@ properties:
         items:
           type: "string"
         type: "array"
    +  AUTH_PASSWORD_VALIDATORS:
    +    default: []
    +    description: >-
    +      A list of dictionaries, describing password validator classes (as strings) and any associated configuration, to
    +      manage validation of passwords for local user accounts. By default, this is an empty list, meaning any password
    +      is permitted.
    +
    +      A future release of Nautobot may change the default value of this setting to increase security.
    +    items:
    +      type: "object"
    +    see_also:
    +      "Django documentation for `AUTH_PASSWORD_VALIDATORS`": "https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS"
    +      "Django documentation for password validators": "https://docs.djangoproject.com/en/stable/topics/auth/passwords/#module-django.contrib.auth.password_validation"
    +    type: "array"
       AUTHENTICATION_BACKENDS:
         default:
         - "nautobot.core.authentication.ObjectPermissionBackend"
    
  • nautobot/docs/user-guide/administration/security/notices.md+36 0 modified
    @@ -4,6 +4,42 @@ As a part of the Nautobot development team's commitment to security, we maintain
     
     <!-- pyml disable-num-lines 500 proper-names -->
     
    +## CVE-2026-34203
    +
    +<!-- pyml disable-next-line no-inline-html -->
    +<table>
    +  <tr>
    +    <th>Disclosure&nbsp;Date</th>
    +    <td>March 30, 2026</td>
    +  </tr>
    +  <tr>
    +    <th>Summary</th>
    +    <td>User creation and editing via the REST API failed to apply the password validation rules defined by Django's <code>AUTH_PASSWORD_VALIDATORS</code> setting (which defaults to an empty list, i.e., no specific rules, but can be configured in Nautobot's <code>nautobot_config.py</code> to apply various rules if desired). This could potentially allow for the creation or modification of users to have passwords that are weak or otherwise do not comply with configured standards.</td>
    +  </tr>
    +  <tr>
    +    <th>Full&nbsp;Description</th>
    +    <td><a href="https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873">GHSA-xmpv-j7p2-j873</a></td>
    +  </tr>
    +  <tr>
    +    <th>Affected&nbsp;Versions</th>
    +    <td>
    +      <ul>
    +        <li>&lt;2.4.30</li>
    +        <li>&ge;3.0.0, &lt;3.0.10</li>
    +      </ul>
    +    </td>
    +  </tr>
    +  <tr>
    +    <th>Patched&nbsp;Versions</th>
    +    <td>
    +      <ul>
    +        <li>2.4.30 (<a href="https://github.com/nautobot/nautobot/pull/8779">patch</a>)</li>
    +        <li>3.0.10 (<a href="https://github.com/nautobot/nautobot/pull/8778">patch</a>)</li>
    +      </ul>
    +    </td>
    +  </tr>
    +</table>
    +
     ## CVE-2025-49142
     
     <!-- pyml disable-next-line no-inline-html -->
    
  • nautobot/users/api/serializers.py+3 0 modified
    @@ -1,6 +1,7 @@
     from django.contrib.auth import authenticate, get_user_model
     from django.contrib.auth.hashers import make_password
     from django.contrib.auth.models import Group
    +from django.contrib.auth.password_validation import validate_password
     from django.contrib.contenttypes.models import ContentType
     from rest_framework import serializers
     from rest_framework.exceptions import ValidationError
    @@ -27,6 +28,8 @@ def validate(self, attrs):
             validated_data = super().validate(attrs)
             if mock_password:
                 validated_data["password"] = None
    +        elif "password" in validated_data:
    +            validate_password(validated_data["password"], user=self.instance)
             return validated_data
     
         def create(self, validated_data):
    
  • nautobot/users/tests/test_api.py+35 0 modified
    @@ -4,6 +4,7 @@
     from django.contrib.auth import get_user_model
     from django.contrib.auth.models import Group
     from django.contrib.contenttypes.models import ContentType
    +from django.test import override_settings
     from django.urls import reverse
     from django.utils.timezone import now
     from rest_framework import HTTP_HEADER_ENCODING, status
    @@ -99,6 +100,20 @@ def test_create_object(self):
                 else:
                     self.assertFalse(user.has_usable_password())
     
    +    @override_settings(
    +        AUTH_PASSWORD_VALIDATORS=[
    +            {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 9}},
    +        ],
    +    )
    +    def test_create_object_password_validation(self):
    +        """Check for https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873 on user creation."""
    +        self.add_permissions("users.add_user")
    +        response = self.client.post(
    +            self._get_list_url(), {"username": "weakuser", "password": "weak"}, format="json", **self.header
    +        )
    +        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
    +        self.assertFalse(User.objects.filter(username="weakuser").exists())
    +
         def test_recreate_object_csv(self):
             """Add validation that the recreated user has no password."""
             super().test_recreate_object_csv()
    @@ -118,6 +133,26 @@ def test_update_object(self):
             user.refresh_from_db()
             self.assertTrue(user.check_password(self.update_data["password"]))
     
    +    @override_settings(
    +        AUTH_PASSWORD_VALIDATORS=[
    +            {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 9}},
    +        ],
    +    )
    +    def test_update_object_password_validation(self):
    +        """Check for https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873 on user update."""
    +        self.add_permissions("users.change_user")
    +        user = self.get_deletable_object()
    +        user.set_password("sufficiently_strong_for_this_test")
    +        user.save()
    +        response = self.client.patch(
    +            self._get_detail_url(user), {"username": "newusername", "password": "weak"}, format="json", **self.header
    +        )
    +        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
    +        user.refresh_from_db()
    +        self.assertNotEqual(user.username, "newusername")
    +        self.assertTrue(user.check_password("sufficiently_strong_for_this_test"))
    +        self.assertFalse(user.check_password("weak"))
    +
         def test_get_put_round_trip(self):
             """Add validation that the password is cleared by a PUT with no specified password."""
             super().test_get_put_round_trip()
    
589f7caf5412

[2.4] Add call to validate_password when managing users via REST API (#8779)

https://github.com/nautobot/nautobotGlenn MatthewsMar 30, 2026via ghsa
5 files changed · +89 0
  • changes/8779.security+1 0 added
    @@ -0,0 +1 @@
    +Added missing enforcement of any configured Django password validators when managing users via the REST API (CVE-2026-34203).
    
  • nautobot/core/settings.yaml+14 0 modified
    @@ -113,6 +113,20 @@ properties:
         items:
           type: "string"
         type: "array"
    +  AUTH_PASSWORD_VALIDATORS:
    +    default: []
    +    description: >-
    +      A list of dictionaries, describing password validator classes (as strings) and any associated configuration, to
    +      manage validation of passwords for local user accounts. By default, this is an empty list, meaning any password
    +      is permitted.
    +
    +      A future release of Nautobot may change the default value of this setting to increase security.
    +    items:
    +      type: "object"
    +    see_also:
    +      "Django documentation for `AUTH_PASSWORD_VALIDATORS`": "https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS"
    +      "Django documentation for password validators": "https://docs.djangoproject.com/en/stable/topics/auth/passwords/#module-django.contrib.auth.password_validation"
    +    type: "array"
       AUTHENTICATION_BACKENDS:
         default:
         - "nautobot.core.authentication.ObjectPermissionBackend"
    
  • nautobot/docs/user-guide/administration/security/notices.md+36 0 modified
    @@ -4,6 +4,42 @@ As a part of the Nautobot development team's commitment to security, we maintain
     
     <!-- pyml disable-num-lines 500 proper-names -->
     
    +## CVE-2026-34203
    +
    +<!-- pyml disable-next-line no-inline-html -->
    +<table>
    +  <tr>
    +    <th>Disclosure&nbsp;Date</th>
    +    <td>March 30, 2026</td>
    +  </tr>
    +  <tr>
    +    <th>Summary</th>
    +    <td>User creation and editing via the REST API failed to apply the password validation rules defined by Django's <code>AUTH_PASSWORD_VALIDATORS</code> setting (which defaults to an empty list, i.e., no specific rules, but can be configured in Nautobot's <code>nautobot_config.py</code> to apply various rules if desired). This could potentially allow for the creation or modification of users to have passwords that are weak or otherwise do not comply with configured standards.</td>
    +  </tr>
    +  <tr>
    +    <th>Full&nbsp;Description</th>
    +    <td><a href="https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873">GHSA-xmpv-j7p2-j873</a></td>
    +  </tr>
    +  <tr>
    +    <th>Affected&nbsp;Versions</th>
    +    <td>
    +      <ul>
    +        <li>&lt;2.4.30</li>
    +        <li>&ge;3.0.0, &lt;3.0.10</li>
    +      </ul>
    +    </td>
    +  </tr>
    +  <tr>
    +    <th>Patched&nbsp;Versions</th>
    +    <td>
    +      <ul>
    +        <li>2.4.30 (<a href="https://github.com/nautobot/nautobot/pull/8779">patch</a>)</li>
    +        <li>3.0.10 (<a href="https://github.com/nautobot/nautobot/pull/8778">patch</a>)</li>
    +      </ul>
    +    </td>
    +  </tr>
    +</table>
    +
     ## CVE-2025-49142
     
     <!-- pyml disable-next-line no-inline-html -->
    
  • nautobot/users/api/serializers.py+3 0 modified
    @@ -1,6 +1,7 @@
     from django.contrib.auth import authenticate, get_user_model
     from django.contrib.auth.hashers import make_password
     from django.contrib.auth.models import Group
    +from django.contrib.auth.password_validation import validate_password
     from django.contrib.contenttypes.models import ContentType
     from rest_framework import serializers
     from rest_framework.exceptions import ValidationError
    @@ -27,6 +28,8 @@ def validate(self, attrs):
             validated_data = super().validate(attrs)
             if mock_password:
                 validated_data["password"] = None
    +        elif "password" in validated_data:
    +            validate_password(validated_data["password"], user=self.instance)
             return validated_data
     
         def create(self, validated_data):
    
  • nautobot/users/tests/test_api.py+35 0 modified
    @@ -4,6 +4,7 @@
     from django.contrib.auth import get_user_model
     from django.contrib.auth.models import Group
     from django.contrib.contenttypes.models import ContentType
    +from django.test import override_settings
     from django.urls import reverse
     from django.utils.timezone import now
     from rest_framework import HTTP_HEADER_ENCODING, status
    @@ -99,6 +100,20 @@ def test_create_object(self):
                 else:
                     self.assertFalse(user.has_usable_password())
     
    +    @override_settings(
    +        AUTH_PASSWORD_VALIDATORS=[
    +            {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 9}},
    +        ],
    +    )
    +    def test_create_object_password_validation(self):
    +        """Check for https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873 on user creation."""
    +        self.add_permissions("users.add_user")
    +        response = self.client.post(
    +            self._get_list_url(), {"username": "weakuser", "password": "weak"}, format="json", **self.header
    +        )
    +        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
    +        self.assertFalse(User.objects.filter(username="weakuser").exists())
    +
         def test_recreate_object_csv(self):
             """Add validation that the recreated user has no password."""
             super().test_recreate_object_csv()
    @@ -118,6 +133,26 @@ def test_update_object(self):
             user.refresh_from_db()
             self.assertTrue(user.check_password(self.update_data["password"]))
     
    +    @override_settings(
    +        AUTH_PASSWORD_VALIDATORS=[
    +            {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 9}},
    +        ],
    +    )
    +    def test_update_object_password_validation(self):
    +        """Check for https://github.com/nautobot/nautobot/security/advisories/GHSA-xmpv-j7p2-j873 on user update."""
    +        self.add_permissions("users.change_user")
    +        user = self.get_deletable_object()
    +        user.set_password("sufficiently_strong_for_this_test")
    +        user.save()
    +        response = self.client.patch(
    +            self._get_detail_url(user), {"username": "newusername", "password": "weak"}, format="json", **self.header
    +        )
    +        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
    +        user.refresh_from_db()
    +        self.assertNotEqual(user.username, "newusername")
    +        self.assertTrue(user.check_password("sufficiently_strong_for_this_test"))
    +        self.assertFalse(user.check_password("weak"))
    +
         def test_get_put_round_trip(self):
             """Add validation that the password is cleared by a PUT with no specified password."""
             super().test_get_put_round_trip()
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.