SEC2-005: Sharing refuses deactivated accounts, but giving a record, group membership and plugin access rules accept them #947

Closed
opened 2026-10-17 10:37:51 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-10-16 in a read-only security review of postulo at 56fc9d531, checked by a second, independent pass.

Severity: Informational · Category: Business Logic · Reference: CWE-284 (Improper Access Control); OWASP A01:2021 (Broken Access Control)

Location:

  • src/postulo/jobs/share_views.py:138-142 (MoveView.principal_from)
  • src/postulo/core/views_access.py:90-98 (GroupsView.post), :190-206 (PluginAccessView._add)

Issue

grantee_from filters is_active=True, so a share can never be made towards a deactivated account. The other three places that name an account as a principal do not:

# share_views.py (superuser only)
        if person and request.user.is_superuser:
            return get_user_model().objects.filter(username__iexact=person.strip()).first()
# views_access.py
            group.user_set.set(get_user_model().objects.filter(pk__in=chosen))
...
            subject = {"person": get_user_model().objects.filter(pk=pk).first()}

A record given to a deactivated account is reachable by nobody until the account is reactivated (the operator can still reach it with everyone=True). A deactivated member kept in a group regains every group record, and every share the group holds, the moment they are reactivated, without any administrator deciding that again.

Impact

Operational rather than exploitable: records can be parked on an account nobody can sign into, and reactivation silently restores access that the people sharing with the group may have assumed ended with the deactivation. PersonActiveView says "nothing deleted, no sign-in", which is accurate but does not mention memberships and shares.

Fix

Filter is_active=True in MoveView.principal_from, the one place a record can be made unreachable. On the groups page, draw inactive accounts greyed with a note rather than excluding them: keeping a deactivated member in a group is consistent with "nothing deleted" and should stay. Extend PersonActiveView's success message to say that group memberships and shares are kept. Done when a test asserts a superuser cannot give a record to a deactivated username and the groups page marks an inactive member as such.

#575 (closed) - a deactivated account kept receiving reminders, webhooks and syncs; about outbound side effects, not about being a principal.

Found on 2026-10-16 in a read-only security review of `postulo` at `56fc9d531`, checked by a second, independent pass. **Severity:** Informational · **Category:** Business Logic · **Reference:** CWE-284 (Improper Access Control); OWASP A01:2021 (Broken Access Control) **Location:** - `src/postulo/jobs/share_views.py:138-142` (`MoveView.principal_from`) - `src/postulo/core/views_access.py:90-98` (`GroupsView.post`), `:190-206` (`PluginAccessView._add`) ## Issue `grantee_from` filters `is_active=True`, so a share can never be made towards a deactivated account. The other three places that name an account as a principal do not: ```python # share_views.py (superuser only) if person and request.user.is_superuser: return get_user_model().objects.filter(username__iexact=person.strip()).first() # views_access.py group.user_set.set(get_user_model().objects.filter(pk__in=chosen)) ... subject = {"person": get_user_model().objects.filter(pk=pk).first()} ``` A record given to a deactivated account is reachable by nobody until the account is reactivated (the operator can still reach it with `everyone=True`). A deactivated member kept in a group regains every group record, and every share the group holds, the moment they are reactivated, without any administrator deciding that again. ## Impact Operational rather than exploitable: records can be parked on an account nobody can sign into, and reactivation silently restores access that the people sharing with the group may have assumed ended with the deactivation. `PersonActiveView` says "nothing deleted, no sign-in", which is accurate but does not mention memberships and shares. ## Fix Filter `is_active=True` in `MoveView.principal_from`, the one place a record can be made unreachable. On the groups page, draw inactive accounts greyed with a note rather than excluding them: keeping a deactivated member in a group is consistent with "nothing deleted" and should stay. Extend `PersonActiveView`'s success message to say that group memberships and shares are kept. Done when a test asserts a superuser cannot give a record to a deactivated username and the groups page marks an inactive member as such. ## Related #575 (closed) - a deactivated account kept receiving reminders, webhooks and syncs; about outbound side effects, not about being a principal.
tiagoagueda added this to the 1.0.0 milestone 2026-10-17 10:37:52 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#947
No description provided.