Deleted Account Still Passes Auth Checks
After an administrator deletes or disables a user account, that user's existing bearer token continues to authenticate successfully and passes authorisation checks on protected endpoints. The authentication middleware verifies only the token's signature and expiry — it never queries the database to confirm the account still exists and is active.
HighBeginnerSecurity testingAPI testingManual testing
// UNDERSTAND
// Symptoms
- A bearer token captured before account deletion returns 200 OK on GET /api/users/me after the account is deleted
- The deleted user can still read, write, or delete records using their pre-deletion token
- Admin-initiated account suspension has no immediate effect on the user's active session
- The token continues to function until its natural expiry (e.g. 24 hours) even though the account no longer exists
// Root Cause
- The authentication middleware validates the JWT signature and expiry time but does not perform a database lookup to confirm the referenced user_id still exists and has an active status. A valid token for a deleted account therefore passes every auth check until the token naturally expires.
- Account deletion does not trigger token revocation — no entry is written to a token blocklist, and the deleted user's tokens continue to function for their full remaining TTL without any mechanism to cut them short.
// Where It Appears
- SaaS applications where admins can delete or suspend user accounts
- HR or enterprise tools where off-boarding requires immediate access revocation
- Applications that use stateless JWT authentication with no token blocklist
- Multi-tenant platforms where a tenant admin removes a team member's account
// REPRODUCE & TEST
// How to Reproduce
- 01Log in as a standard user and capture the bearer token from any authenticated request in DevTools
- 02Confirm the token works by sending GET /api/users/me with the bearer token and noting the 200 response
- 03In the admin panel, delete or disable the user account
- 04Send GET /api/users/me again using the same bearer token captured in step 1
- 05If the response is 200 with user data, the deleted account is still passing auth checks
// Test Data Needed
- A standard user account that can be deleted or disabled via the admin panel
- The bearer token captured from an authenticated request before the account is deleted
- Admin access to delete or disable accounts
// Manual Testing Ideas
- Delete a test account in the admin panel and immediately attempt API calls using the pre-deletion token — confirm whether they succeed or return 401
- Disable (rather than delete) the account and test the same token to check whether disabled accounts are treated differently from deleted ones
- Test the browser session as well as the API token — after an admin deletes the account, can the user still navigate the app in an open browser tab?
- Test off-boarding scenarios: remove a user from a team workspace and confirm their token no longer has access to that workspace's resources
- Check whether the application has a 'force logout all sessions' feature and whether it correctly invalidates tokens
// API Testing Ideas
- Authenticate as the test user and capture the bearer token
- Send GET /api/users/me with the token; assert the response is 200 — confirming the token is valid before deletion
- Via the admin API or panel, delete or disable the test user account
- Send GET /api/users/me again with the same bearer token
- Assert the response is 401 Unauthorized or 403 Forbidden — if it is 200, the deleted account is still authenticated
// Automation Idea
Capture a valid bearer token for a test user. Call the admin API to delete or disable the account (DELETE /api/admin/users/{id}). Immediately send GET /api/users/me with the captured token and assert the response is 401 or 403. A 200 confirms the token was not invalidated on account deletion.
// Expected Result
Immediately after an account is deleted or disabled, all bearer tokens associated with that account are rejected with 401 Unauthorized or 403 Forbidden.
// Actual Result (Example)
After an admin deletes the test user account, GET /api/users/me with the pre-deletion bearer token returns 200 OK and the full user profile. The deleted account's token remains valid for its remaining TTL.
// REPORT IT
Example Bug Report
- Title
- Bearer token from deleted account still returns 200 on GET /api/users/me
- Severity
- High
- Environment
- Staging environment Postman Admin account + standard test user account Bearer token captured before account deletion
- Steps to Reproduce
- 01Log in as the test user and copy the bearer token from any authenticated request
- 02Send GET /api/users/me with the bearer token; confirm the response is 200
- 03Log in as admin and delete the test user account from the admin panel
- 04Send GET /api/users/me with the same pre-deletion bearer token
- Expected Result
- The response is 401 Unauthorized — the token is no longer valid.
- Actual Result
- The response is 200 OK with the deleted user's full profile data. The bearer token from a deleted account continues to authenticate successfully.
- Impact
- Off-boarded employees or suspended users retain full API access until their token naturally expires. In applications with long token TTLs (e.g. 24 hours), this creates a significant window during which a terminated user can exfiltrate data or take harmful actions.