VYPR
Moderate severityNVD Advisory· Published May 28, 2024· Updated Aug 2, 2024

Nautobot dynamic-group-members doesn't enforce permission restrictions on member objects

CVE-2024-36112

Description

Nautobot is a Network Source of Truth and Network Automation Platform. A user with permissions to view Dynamic Group records (extras.view_dynamicgroup permission) can use the Dynamic Group detail UI view (/extras/dynamic-groups//) and/or the members REST API view (/api/extras/dynamic-groups//members/) to list the objects that are members of a given Dynamic Group. In versions of Nautobot between 1.3.0 (where the Dynamic Groups feature was added) and 1.6.22 inclusive, and 2.0.0 through 2.2.4 inclusive, Nautobot fails to restrict these listings based on the member object permissions - for example a Dynamic Group of Device objects will list all Devices that it contains, regardless of the user's dcim.view_device permissions or lack thereof. This issue has been fixed in Nautobot versions 1.6.23 and 2.2.5. Users are advised to upgrade. This vulnerability can be partially mitigated by removing extras.view_dynamicgroup permission from users however a full fix will require upgrading.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Nautobot Dynamic Groups UI and API list member objects without checking user permissions on those objects.

Root

Cause

Nautobot is a Network Source of Truth and Network Automation Platform. The Dynamic Groups feature, introduced in version 1.3.0, allows users with the extras.view_dynamicgroup permission to view group details and list group members via the UI (/extras/dynamic-groups//) or REST API (/api/extras/dynamic-groups//members/). However, in versions 1.3.0 through 1.6.22 and 2.0.0 through 2.2.4, Nautobot fails to enforce the appropriate object-level permissions (e.g., dcim.view_device) on the member objects themselves. This means a user who can view a Dynamic Group of Devices will see all Devices in that group, even if they lack dcim.view_device permission [1].

Attack

Surface and Exploitation

The attack surface is the Dynamic Group detail view and the members API endpoint. To exploit this, an attacker must have a Nautobot account with the extras.view_dynamicgroup permission. No additional authentication or network position is required beyond that. The vulnerability is a straightforward authorization bypass: the platform checks the user's permission to view the Dynamic Group but does not check permissions on the returned member objects. An attacker can simply navigate to the UI or call the API to enumerate all members of any Dynamic Group they can see [1].

Impact

An attacker can list all objects that belong to any Dynamic Group they have visibility of, regardless of their permissions on those object types. For example, a user with no dcim.view_device permission could see all devices in a group, potentially exposing sensitive inventory data. This affects any object type that can be part of a Dynamic Group, such as devices, circuits, or prefixes, and could lead to unauthorized disclosure of network topology or asset information [1].

Mitigation

This issue is fixed in Nautobot versions 1.6.23 and 2.2.5 [1][2][3][4]. The fix adds permission checks ensuring that the member listing only returns objects the user is authorized to view. Users are advised to upgrade. A partial workaround is to remove the extras.view_dynamicgroup permission from users, but this also prevents legitimate use of Dynamic Groups; upgrading is the complete solution [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
nautobotPyPI
>= 1.3.0, < 1.6.231.6.23
nautobotPyPI
>= 2.0.0, < 2.2.52.2.5

Affected products

2
  • ghsa-coords
    Range: >= 1.3.0, < 1.6.23
  • nautobot/nautobotv5
    Range: >= 1.3.0, < 1.6.23

Patches

2
3a63aa1327f9

[LTM] Dynamic groups permissions improvements (#5762)

https://github.com/nautobot/nautobotGlenn MatthewsMay 28, 2024via ghsa
7 files changed · +85 11
  • changes/5762.security+1 0 added
    @@ -0,0 +1 @@
    +Fixed missing member object permission enforcement (e.g., enforce Device permissions for a Dynamic Group containing Devices) when viewing Dynamic Group member objects in the UI or REST API ([GHSA-qmjf-wc2h-6x3q](https://github.com/nautobot/nautobot/security/advisories/GHSA-qmjf-wc2h-6x3q)).
    
  • nautobot/extras/api/views.py+2 2 modified
    @@ -330,13 +330,13 @@ class DynamicGroupViewSet(ModelViewSet, NotesViewSetMixin):
         # @extend_schema(methods=["get"], responses={200: member_response})
         @action(detail=True, methods=["get"])
         def members(self, request, pk, *args, **kwargs):
    -        """List member objects of the same type as the `content_type` for this dynamic group."""
    +        """List the member objects of this dynamic group."""
             instance = get_object_or_404(self.queryset, pk=pk)
     
             # Retrieve the serializer for the content_type and paginate the results
             member_model_class = instance.content_type.model_class()
             member_serializer_class = get_serializer_for_model(member_model_class)
    -        members = self.paginate_queryset(instance.members)
    +        members = self.paginate_queryset(instance.members.restrict(request.user, "view"))
             member_serializer = member_serializer_class(members, many=True, context={"request": request})
             return self.get_paginated_response(member_serializer.data)
     
    
  • nautobot/extras/tests/test_api.py+23 1 modified
    @@ -69,6 +69,7 @@
     from nautobot.ipam.models import VLAN, VLANGroup
     from nautobot.users.models import ObjectPermission
     from nautobot.utilities.choices import ColorChoices
    +from nautobot.utilities.permissions import get_permission_for_model
     from nautobot.utilities.testing import APITestCase, APIViewTestCases
     from nautobot.utilities.testing.utils import disable_warnings
     from nautobot.utilities.utils import get_route_for_model, slugify_dashes_to_underscores
    @@ -752,13 +753,34 @@ class DynamicGroupTest(DynamicGroupTestMixin, APIViewTestCases.APIViewTestCase):
         def test_get_members(self):
             """Test that the `/members/` API endpoint returns what is expected."""
             self.add_permissions("extras.view_dynamicgroup")
    -        instance = DynamicGroup.objects.first()
    +        instance = self.groups[0]
    +        self.add_permissions(get_permission_for_model(instance.content_type.model_class(), "view"))
             member_count = instance.members.count()
             url = reverse("extras-api:dynamicgroup-members", kwargs={"pk": instance.pk})
             response = self.client.get(url, **self.header)
             self.assertHttpStatus(response, status.HTTP_200_OK)
             self.assertEqual(member_count, len(response.json()["results"]))
     
    +    def test_get_members_with_constrained_permission(self):
    +        """Test that the `/members/` API endpoint enforces permissions on the member model."""
    +        self.add_permissions("extras.view_dynamicgroup")
    +        instance = self.groups[0]
    +        obj1 = instance.members.first()
    +        obj_perm = ObjectPermission(
    +            name="Test permission",
    +            constraints={"pk__in": [obj1.pk]},
    +            actions=["view"],
    +        )
    +        obj_perm.save()
    +        obj_perm.users.add(self.user)
    +        obj_perm.object_types.add(instance.content_type)
    +
    +        url = reverse("extras-api:dynamicgroup-members", kwargs={"pk": instance.pk})
    +        response = self.client.get(url, **self.header)
    +        self.assertHttpStatus(response, status.HTTP_200_OK)
    +        self.assertEqual(len(response.json()["results"]), 1)
    +        self.assertEqual(response.json()["results"][0]["id"], str(obj1.pk))
    +
     
     class DynamicGroupMembershipTest(DynamicGroupTestMixin, APIViewTestCases.APIViewTestCase):
         model = DynamicGroupMembership
    
  • nautobot/extras/tests/test_dynamicgroups.py+1 1 modified
    @@ -1002,7 +1002,7 @@ def all(self):
                 group.members_cached
                 self.assertEqual(mock_get_queryset.call_count, 1)
     
    -            time.sleep(2)  # Let the cache expire
    +            time.sleep(3)  # Let the cache expire
     
                 group.members_cached
                 self.assertEqual(mock_get_queryset.call_count, 2)
    
  • nautobot/extras/tests/test_views.py+48 4 modified
    @@ -66,6 +66,7 @@
     from nautobot.ipam.factory import VLANFactory
     from nautobot.ipam.models import VLAN, VLANGroup
     from nautobot.users.models import ObjectPermission
    +from nautobot.utilities.permissions import get_permission_for_model
     from nautobot.utilities.testing import ViewTestCases, TestCase, extract_page_body, extract_form_failures
     from nautobot.utilities.testing.utils import disable_warnings, post_data
     from nautobot.utilities.utils import slugify_dashes_to_underscores
    @@ -614,9 +615,11 @@ def setUpTestData(cls):
             content_type = ContentType.objects.get_for_model(Device)
     
             # DynamicGroup objects to test.
    -        DynamicGroup.objects.create(name="DG 1", slug="dg-1", content_type=content_type)
    -        DynamicGroup.objects.create(name="DG 2", slug="dg-2", content_type=content_type)
    -        DynamicGroup.objects.create(name="DG 3", slug="dg-3", content_type=content_type)
    +        cls.dynamic_groups = [
    +            DynamicGroup.objects.create(name="DG 1", slug="dg-1", content_type=content_type),
    +            DynamicGroup.objects.create(name="DG 2", slug="dg-2", content_type=content_type),
    +            DynamicGroup.objects.create(name="DG 3", slug="dg-3", content_type=content_type),
    +        ]
     
             manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
             devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
    @@ -637,6 +640,38 @@ def setUpTestData(cls):
                 "dynamic_group_memberships-MAX_NUM_FORMS": "1000",
             }
     
    +    def test_get_object_with_permission(self):
    +        instance = self._get_queryset().first()
    +        # Add view permissions for the group's members:
    +        self.add_permissions(get_permission_for_model(instance.content_type.model_class(), "view"))
    +
    +        response = super().test_get_object_with_permission()
    +
    +        response_body = extract_page_body(response.content.decode(response.charset))
    +        # Check that the "members" table in the detail view includes all appropriate member objects
    +        for member in instance.members:
    +            self.assertIn(str(member.pk), response_body)
    +
    +    def test_get_object_with_constrained_permission(self):
    +        instance = self._get_queryset().first()
    +        # Add view permission for one of the group's members but not the others:
    +        member1, member2 = instance.members[:2]
    +        obj_perm = ObjectPermission(
    +            name="Members permission",
    +            constraints={"pk": member1.pk},
    +            actions=["view"],
    +        )
    +        obj_perm.save()
    +        obj_perm.users.add(self.user)
    +        obj_perm.object_types.add(instance.content_type)
    +
    +        response = super().test_get_object_with_constrained_permission()
    +
    +        response_body = extract_page_body(response.content.decode(response.charset))
    +        # Check that the "members" table in the detail view includes all permitted member objects
    +        self.assertIn(str(member1.pk), response_body)
    +        self.assertNotIn(str(member2.pk), response_body)
    +
         def test_get_object_dynamic_groups_anonymous(self):
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
             self.client.logout()
    @@ -660,7 +695,6 @@ def test_get_object_dynamic_groups_with_permission(self):
             self.assertIn("DG 3", response_body, msg=response_body)
     
         def test_get_object_dynamic_groups_with_constrained_permission(self):
    -        self.add_permissions("extras.view_dynamicgroup")
             obj_perm = ObjectPermission(
                 name="View a device",
                 constraints={"pk": Device.objects.first().pk},
    @@ -669,12 +703,22 @@ def test_get_object_dynamic_groups_with_constrained_permission(self):
             obj_perm.save()
             obj_perm.users.add(self.user)
             obj_perm.object_types.add(ContentType.objects.get_for_model(Device))
    +        obj_perm_2 = ObjectPermission(
    +            name="View a Dynamic Group",
    +            constraints={"pk": self.dynamic_groups[0].pk},
    +            actions=["view"],
    +        )
    +        obj_perm_2.save()
    +        obj_perm_2.users.add(self.user)
    +        obj_perm_2.object_types.add(ContentType.objects.get_for_model(DynamicGroup))
     
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
             response = self.client.get(url)
             self.assertHttpStatus(response, 200)
             response_body = response.content.decode(response.charset)
             self.assertIn("DG 1", response_body, msg=response_body)
    +        self.assertNotIn("DG 2", response_body, msg=response_body)
    +        self.assertNotIn("DG 3", response_body, msg=response_body)
     
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.last().pk})
             response = self.client.get(url)
    
  • nautobot/extras/views.py+4 2 modified
    @@ -550,7 +550,7 @@ def get_extra_context(self, request, instance):
     
             if table_class is not None:
                 # Members table (for display on Members nav tab)
    -            members_table = table_class(instance.members, orderable=False)
    +            members_table = table_class(instance.members.restrict(request.user, "view"), orderable=False)
                 paginate = {
                     "paginator_class": EnhancedPaginator,
                     "per_page": get_paginate_count(request),
    @@ -722,7 +722,9 @@ def get(self, request, model, **kwargs):
                 obj = get_object_or_404(model, **kwargs)
     
             # Gather all dynamic groups for this object (and its related objects)
    -        dynamicsgroups_table = tables.DynamicGroupTable(data=obj.dynamic_groups_cached, orderable=False)
    +        dynamicsgroups_table = tables.DynamicGroupTable(
    +            data=obj.dynamic_groups_cached.restrict(request.user, "view"), orderable=False
    +        )
     
             # Apply the request context
             paginate = {
    
  • nautobot/utilities/testing/views.py+6 1 modified
    @@ -209,6 +209,8 @@ def test_get_object_with_permission(self):
                                 escape(str(instance.cf.get(custom_field.name) or "")), response_body, msg=response_body
                             )
     
    +            return response  # for consumption by child test cases if desired
    +
             @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
             def test_get_object_with_constrained_permission(self):
                 instance1, instance2 = self._get_queryset().all()[:2]
    @@ -226,11 +228,14 @@ def test_get_object_with_constrained_permission(self):
                 obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
     
                 # Try GET to permitted object
    -            self.assertHttpStatus(self.client.get(instance1.get_absolute_url()), 200)
    +            response = self.client.get(instance1.get_absolute_url())
    +            self.assertHttpStatus(response, 200)
     
                 # Try GET to non-permitted object
                 self.assertHttpStatus(self.client.get(instance2.get_absolute_url()), 404)
     
    +            return response  # for consumption by child test cases if desired
    +
             @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
             def test_has_advanced_tab(self):
                 instance = self._get_queryset().first()
    
4d1ff2abe277

Dynamic group permissions improvements (#5757)

https://github.com/nautobot/nautobotGlenn MatthewsMay 28, 2024via ghsa
6 files changed · +85 11
  • changes/5757.security+1 0 added
    @@ -0,0 +1 @@
    +Fixed missing member object permission enforcement (e.g., enforce Device permissions for a Dynamic Group containing Devices) when viewing Dynamic Group member objects in the UI or REST API ([GHSA-qmjf-wc2h-6x3q](https://github.com/nautobot/nautobot/security/advisories/GHSA-qmjf-wc2h-6x3q)).
    
  • nautobot/core/testing/views.py+6 1 modified
    @@ -213,6 +213,8 @@ def test_get_object_with_permission(self):
                                 escape(str(instance.cf.get(custom_field.key) or "")), response_body, msg=response_body
                             )
     
    +            return response  # for consumption by child test cases if desired
    +
             @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
             def test_get_object_with_constrained_permission(self):
                 instance1, instance2 = self._get_queryset().all()[:2]
    @@ -230,11 +232,14 @@ def test_get_object_with_constrained_permission(self):
                 obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
     
                 # Try GET to permitted object
    -            self.assertHttpStatus(self.client.get(instance1.get_absolute_url()), 200)
    +            response = self.client.get(instance1.get_absolute_url())
    +            self.assertHttpStatus(response, 200)
     
                 # Try GET to non-permitted object
                 self.assertHttpStatus(self.client.get(instance2.get_absolute_url()), 404)
     
    +            return response  # for consumption by child test cases if desired
    +
             @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
             def test_has_advanced_tab(self):
                 instance = self._get_queryset().first()
    
  • nautobot/extras/api/views.py+2 2 modified
    @@ -304,13 +304,13 @@ class DynamicGroupViewSet(NotesViewSetMixin, ModelViewSet):
         # @extend_schema(methods=["get"], responses={200: member_response})
         @action(detail=True, methods=["get"])
         def members(self, request, pk, *args, **kwargs):
    -        """List member objects of the same type as the `content_type` for this dynamic group."""
    +        """List the member objects of this dynamic group."""
             instance = get_object_or_404(self.queryset, pk=pk)
     
             # Retrieve the serializer for the content_type and paginate the results
             member_model_class = instance.content_type.model_class()
             member_serializer_class = get_serializer_for_model(member_model_class)
    -        members = self.paginate_queryset(instance.members)
    +        members = self.paginate_queryset(instance.members.restrict(request.user, "view"))
             member_serializer = member_serializer_class(members, many=True, context={"request": request})
             return self.get_paginated_response(member_serializer.data)
     
    
  • nautobot/extras/tests/test_api.py+24 2 modified
    @@ -17,6 +17,7 @@
     from nautobot.core.testing import APITestCase, APIViewTestCases
     from nautobot.core.testing.utils import disable_warnings
     from nautobot.core.utils.lookup import get_route_for_model
    +from nautobot.core.utils.permissions import get_permission_for_model
     from nautobot.dcim.models import (
         Controller,
         Device,
    @@ -768,7 +769,7 @@ def setUpTestData(cls):
     
             # Then the DynamicGroups.
             cls.content_type = ContentType.objects.get_for_model(Device)
    -        cls.groups = cls.groups = [
    +        cls.groups = [
                 DynamicGroup.objects.create(
                     name="API DynamicGroup 1",
                     content_type=cls.content_type,
    @@ -811,13 +812,34 @@ class DynamicGroupTest(DynamicGroupTestMixin, APIViewTestCases.APIViewTestCase):
         def test_get_members(self):
             """Test that the `/members/` API endpoint returns what is expected."""
             self.add_permissions("extras.view_dynamicgroup")
    -        instance = DynamicGroup.objects.first()
    +        instance = self.groups[0]
    +        self.add_permissions(get_permission_for_model(instance.content_type.model_class(), "view"))
             member_count = instance.members.count()
             url = reverse("extras-api:dynamicgroup-members", kwargs={"pk": instance.pk})
             response = self.client.get(url, **self.header)
             self.assertHttpStatus(response, status.HTTP_200_OK)
             self.assertEqual(member_count, len(response.json()["results"]))
     
    +    def test_get_members_with_constrained_permission(self):
    +        """Test that the `/members/` API endpoint enforces permissions on the member model."""
    +        self.add_permissions("extras.view_dynamicgroup")
    +        instance = self.groups[0]
    +        obj1 = instance.members.first()
    +        obj_perm = ObjectPermission(
    +            name="Test permission",
    +            constraints={"pk__in": [obj1.pk]},
    +            actions=["view"],
    +        )
    +        obj_perm.save()
    +        obj_perm.users.add(self.user)
    +        obj_perm.object_types.add(instance.content_type)
    +
    +        url = reverse("extras-api:dynamicgroup-members", kwargs={"pk": instance.pk})
    +        response = self.client.get(url, **self.header)
    +        self.assertHttpStatus(response, status.HTTP_200_OK)
    +        self.assertEqual(len(response.json()["results"]), 1)
    +        self.assertEqual(response.json()["results"][0]["id"], str(obj1.pk))
    +
     
     class DynamicGroupMembershipTest(DynamicGroupTestMixin, APIViewTestCases.APIViewTestCase):
         model = DynamicGroupMembership
    
  • nautobot/extras/tests/test_views.py+48 4 modified
    @@ -17,6 +17,7 @@
     from nautobot.core.models.fields import slugify_dashes_to_underscores
     from nautobot.core.testing import extract_form_failures, extract_page_body, TestCase, ViewTestCases
     from nautobot.core.testing.utils import disable_warnings, post_data
    +from nautobot.core.utils.permissions import get_permission_for_model
     from nautobot.dcim.models import (
         ConsolePort,
         Controller,
    @@ -777,9 +778,11 @@ def setUpTestData(cls):
             content_type = ContentType.objects.get_for_model(Device)
     
             # DynamicGroup objects to test.
    -        DynamicGroup.objects.create(name="DG 1", content_type=content_type)
    -        DynamicGroup.objects.create(name="DG 2", content_type=content_type)
    -        DynamicGroup.objects.create(name="DG 3", content_type=content_type)
    +        cls.dynamic_groups = [
    +            DynamicGroup.objects.create(name="DG 1", content_type=content_type),
    +            DynamicGroup.objects.create(name="DG 2", content_type=content_type),
    +            DynamicGroup.objects.create(name="DG 3", content_type=content_type),
    +        ]
     
             cls.form_data = {
                 "name": "new_dynamic_group",
    @@ -792,6 +795,38 @@ def setUpTestData(cls):
                 "dynamic_group_memberships-MAX_NUM_FORMS": "1000",
             }
     
    +    def test_get_object_with_permission(self):
    +        instance = self._get_queryset().first()
    +        # Add view permissions for the group's members:
    +        self.add_permissions(get_permission_for_model(instance.content_type.model_class(), "view"))
    +
    +        response = super().test_get_object_with_permission()
    +
    +        response_body = extract_page_body(response.content.decode(response.charset))
    +        # Check that the "members" table in the detail view includes all appropriate member objects
    +        for member in instance.members:
    +            self.assertIn(str(member.pk), response_body)
    +
    +    def test_get_object_with_constrained_permission(self):
    +        instance = self._get_queryset().first()
    +        # Add view permission for one of the group's members but not the others:
    +        member1, member2 = instance.members[:2]
    +        obj_perm = ObjectPermission(
    +            name="Members permission",
    +            constraints={"pk": member1.pk},
    +            actions=["view"],
    +        )
    +        obj_perm.save()
    +        obj_perm.users.add(self.user)
    +        obj_perm.object_types.add(instance.content_type)
    +
    +        response = super().test_get_object_with_constrained_permission()
    +
    +        response_body = extract_page_body(response.content.decode(response.charset))
    +        # Check that the "members" table in the detail view includes all permitted member objects
    +        self.assertIn(str(member1.pk), response_body)
    +        self.assertNotIn(str(member2.pk), response_body)
    +
         def test_get_object_dynamic_groups_anonymous(self):
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
             self.client.logout()
    @@ -815,7 +850,6 @@ def test_get_object_dynamic_groups_with_permission(self):
             self.assertIn("DG 3", response_body, msg=response_body)
     
         def test_get_object_dynamic_groups_with_constrained_permission(self):
    -        self.add_permissions("extras.view_dynamicgroup")
             obj_perm = ObjectPermission(
                 name="View a device",
                 constraints={"pk": Device.objects.first().pk},
    @@ -824,12 +858,22 @@ def test_get_object_dynamic_groups_with_constrained_permission(self):
             obj_perm.save()
             obj_perm.users.add(self.user)
             obj_perm.object_types.add(ContentType.objects.get_for_model(Device))
    +        obj_perm_2 = ObjectPermission(
    +            name="View a Dynamic Group",
    +            constraints={"pk": self.dynamic_groups[0].pk},
    +            actions=["view"],
    +        )
    +        obj_perm_2.save()
    +        obj_perm_2.users.add(self.user)
    +        obj_perm_2.object_types.add(ContentType.objects.get_for_model(DynamicGroup))
     
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
             response = self.client.get(url)
             self.assertHttpStatus(response, 200)
             response_body = response.content.decode(response.charset)
             self.assertIn("DG 1", response_body, msg=response_body)
    +        self.assertNotIn("DG 2", response_body, msg=response_body)
    +        self.assertNotIn("DG 3", response_body, msg=response_body)
     
             url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.last().pk})
             response = self.client.get(url)
    
  • nautobot/extras/views.py+4 2 modified
    @@ -704,7 +704,7 @@ def get_extra_context(self, request, instance):
     
             if table_class is not None:
                 # Members table (for display on Members nav tab)
    -            members_table = table_class(instance.members, orderable=False)
    +            members_table = table_class(instance.members.restrict(request.user, "view"), orderable=False)
                 paginate = {
                     "paginator_class": EnhancedPaginator,
                     "per_page": get_paginate_count(request),
    @@ -884,7 +884,9 @@ def get(self, request, model, **kwargs):
                 obj = get_object_or_404(model, **kwargs)
     
             # Gather all dynamic groups for this object (and its related objects)
    -        dynamicsgroups_table = tables.DynamicGroupTable(data=obj.dynamic_groups_cached, orderable=False)
    +        dynamicsgroups_table = tables.DynamicGroupTable(
    +            data=obj.dynamic_groups_cached.restrict(request.user, "view"), orderable=False
    +        )
     
             # Apply the request context
             paginate = {
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.