Skip to content

Security: account deletion/disable does not revoke the user's other active sessions (SUF-03) #329

Description

@devondragon

Summary

The ordinary self-service account deletion/disable flow logs out only the current request. It does not invalidate the user's other active sessions, even though SessionInvalidationService.invalidateUserSessions() already exists and the GDPR deletion path uses it.

Severity: High

Affected code

  • src/main/java/com/digitalsanctuary/spring/user/api/UserAPI.javadeleteAccount (~389), logoutUser (~589): only SecurityContextHolder.clearContext() + request.logout() for the current request.
  • src/main/java/com/digitalsanctuary/spring/user/service/UserService.javadeleteOrDisableUser (~500): no session invalidation in either branch.
  • Contrast: src/main/java/com/digitalsanctuary/spring/user/api/GdprAPI.java:297 — the GDPR path does call invalidateUserSessions() ("invalidates ALL sessions across all devices").

Details

Default deletion is soft-delete (user.actuallyDeleteAccount=false), which sets enabled=false and saves. DSUserDetails caches authorities and the enabled flag at login time, and there is no per-request re-check against the database, so other established sessions remain fully authorized until natural expiry. The same holds for hard delete — a cached principal continues to authenticate after the backing row is removed. Sessions are already registered in the SessionRegistry (WebSecurityConfig.java:160), so revocation is available; the ordinary path simply doesn't invoke it.

Impact

A user who deletes or disables an account (e.g. because it was compromised) reasonably expects all sessions to end. Any other active session continues to have access until it expires (CWE-613).

Recommended fix

  • Call sessionInvalidationService.invalidateUserSessions(user) in the ordinary delete/disable flow, for both soft and hard deletion.
  • Prefer placing revocation at the service layer or an after-commit listener so direct callers of deleteOrDisableUser() cannot bypass it.
  • Add a two-session integration test proving both soft-disable and hard-delete terminate the second session.

Identified during a code-first security assessment of the current main branch. The GDPR path already demonstrates the intended pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecurity

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions