Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/pentesting-web/login-bypass/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,48 @@ If the page has "**Remember Me**" functionality check how is it implemented and

Pages usually redirects users after login, check if you can alter that redirect to cause an [**Open Redirect**](../open-redirect.md). Maybe you can steal some information (codes, cookies...) if you redirect the user to your web.

### Client-side authentication & authorization bypass in SPAs

Some applications only protect routes/actions in the **frontend** (route guards, hidden buttons, `localStorage` / `sessionStorage`, feature flags, or JSON fields such as `role`, `groups`, `is_active`, `PluginId`, `TimeoutStatus`). If the **backend APIs don't re-check authentication and authorization**, you can often unlock the whole UI or perform the action directly.

Quick workflow:

1. **Read the JS bundle** (`main.js`, chunks, source maps) and search for `authRequired`, `beforeEach`, `isUserLoggedIn`, `localStorage`, `sessionStorage`, `userInfo`, `token`, `exp`, `role`, `groups`, `is_active`, `PluginId`, `TimeoutStatus`.
2. **Locate the trust boundary**: identify whether the SPA only checks that a storage key exists, a date is in the future, or a JSON field is truthy.
3. **Forge the expected state** in DevTools or intercept proxy traffic to modify the relevant response fields.
4. **Validate impact server-side** by performing the hidden action or calling the API directly. If the server accepts it, this is a real auth/authz bypass, not just a cosmetic UI issue.

Common patterns:

- **Storage-only login check**: if `isUserLoggedIn()` only checks `localStorage.getItem("token")` and whether `tokenExpiry` is in the future, set both values manually and reload.
- **JWT-like parsing without verification**: if frontend code only splits `token` on `.`, base64url-decodes the payload, and reads claims like `_id` or `exp`, any syntactically valid JWT-like value with the expected claims may satisfy the SPA unless the backend verifies it.
- **Truthy-object resolver**: if a route resolver only checks `if (userInfo)`, `sessionStorage.setItem("userInfo", JSON.stringify({}))` is often enough because `{}` is valid JSON and truthy.
- **Response-driven authorization**: intercept endpoints such as `GetSessionInfo` / `GetNotifications` and replace `null` / `false` values in fields like `Groups`, `PluginId`, or `UserCanUpdate*`; also try removing logout indicators such as `"TimeoutStatus":"Timeout"`.
- **UI-only privilege flags**: flip booleans such as `is_active`, `canEdit`, `isAdmin`, or feature flags in profile/account responses to reveal hidden functionality, then try the newly exposed write action.

Examples:

```javascript
localStorage.setItem("token", "<jwt-like-value>");
localStorage.setItem("tokenExpiry", "2030-01-01T00:00:00Z");

sessionStorage.setItem("userInfo", JSON.stringify({}));
sessionStorage.setItem("loggedIn", JSON.stringify(true));
```

```json
{
"Groups": ["Production Admin"],
"PluginId": "<copied-or-guessed-value>",
"UserCanUpdateRunningOrder": true,
"UserCanUpdateText": true
}
```

> [!TIP]
> If the page only unlocks after you change the frontend state but the API still returns `401` / `403`, the finding is probably just a **client-side-only UI bypass**. The real vulnerability exists when backend endpoints also trust that client-controlled state.


## Other Checks

- Check if you can **enumerate usernames** abusing the login functionality.
Expand All @@ -97,6 +139,10 @@ Pages usually redirects users after login, check if you can alter that redirect



## References

- [Client-side Authentication Bypass](https://kuldeep.io/posts/client-side-authentication-bypass/)

{{#include ../../banners/hacktricks-training.md}}