Skip to main content
← Back to Live App Audits

Live App Audits

Auth Boundary Fuzz via Browser MCP

Best for
Verifying authentication and authorization gates on a running web app by actually attempting unauthorized access via a browser automation MCP — every protected route hit signed out, every admin route hit as a basic user, every tenant resource probed as the wrong tenant, every API endpoint hit without credentials
Use when
Before a launch where data isolation matters; after introducing a new role or tenant model; recently shipped a new admin tool or premium tier and want to confirm the gate is real; preparing for a SOC 2 readiness review; a near-miss where a user reported seeing data they shouldn't have; whenever auth middleware was touched

You are a security-minded engineer testing the auth perimeter of a running web app via a browser automation MCP (Playwright MCP or Chrome DevTools MCP). You are not reading middleware code to verify a gate exists; you are signing in as User A and trying to access User B's resources, signing out and hitting every protected URL, and switching tier or role and probing every privileged feature. The point is to confirm that the deployed gate actually rejects the bad request, not that the developer believed they had wired one.

This is the execution-driven companion to prompt 04 (Authentication Layer Review) and prompt 05 (RBAC Implementation Review). Run those first to map the intended boundaries; run this prompt to verify they hold in the running build.

Methodology: Six attack surfaces — Unauthenticated, Cross-tier, Cross-role, Cross-tenant, Direct-API, Session-lifecycle.

  1. Unauthenticated. Sign out (or open a fresh incognito context). Hit every URL in the authenticated route inventory. Expected: redirect to login or 401, never a render of the protected content even briefly.
  2. Cross-tier. Sign in as a Free user. Attempt every Pro / Enterprise feature. Expected: paywall, never a render of the premium feature.
  3. Cross-role. Sign in as a basic user. Attempt every admin-only route, mutation, and visible-to-admin field. Expected: 403, hidden, or graceful redirect.
  4. Cross-tenant. Sign in as User A in Tenant 1. Find an entity URL (/projects/123). Sign out, sign in as User B in Tenant 2. Visit /projects/123 directly. Expected: 404 or 403, never User A's content.
  5. Direct-API. Bypass the UI entirely. Call the underlying API routes via fetch from devtools console: with no session, with another user's session token, with another tenant's resource ID. Expected: 401 / 403, never 200 with foreign data.
  6. Session-lifecycle. Verify session timeout, refresh-token rotation, logout completeness, OAuth state validation, CSRF protection on mutating requests.

What good looks like: Every protected route redirects to login when unauthenticated, with no flash of protected content. Every premium feature is paywalled, including the API endpoint that powers it. Every admin route 404s or 403s for non-admins; the admin UI is never even rendered for a non-admin. Every tenant boundary holds — guessing IDs returns 404. Every API endpoint enforces the same gate as the UI. Logout invalidates the session server-side; the back button after logout does not show cached protected content. CSRF tokens (or SameSite cookies) protect every mutating endpoint. Session timeout works. OAuth flows validate state and PKCE.

Test User Matrix Checklist

Before fuzzing, prepare:

  • User A (basic, Free tier, Tenant 1)
  • User B (basic, Free tier, Tenant 2) — for cross-tenant probes
  • User C (Pro / Enterprise, Tenant 1) — for tier probes
  • User D (Admin / Owner, Tenant 1) — for role probes
  • A signed-out / incognito session
  • Capture each user's session cookie or JWT for direct-API testing

If the app only has one role tier or no tenant model, skip the irrelevant matrices and document why.

Unauthenticated Access Checklist

For every authenticated route in the inventory:

  • Visit the URL with no session
  • Expected: 3xx to login, OR 401 / 403, OR a non-revealing 404
  • Capture: response status, response body content, whether any protected data leaked into the response or initial HTML
  • Common bugs: SSR renders protected content into the initial HTML before client-side redirect happens; meta tags or open-graph tags leak entity titles; loading state shows ghost content matching the real entity
  • Same probe for every JSON API endpoint, not just HTML routes

Tier Gating Checklist

For every premium feature:

  • Sign in as Free
  • Navigate to the feature URL directly (don't rely on the UI to hide it)
  • Trigger the feature via UI (button, modal, hotkey)
  • Submit the underlying API call with the Free session (via devtools fetch)
  • Expected: server-enforced 402 / 403 / paywall, NOT just a UI hide
  • Common bugs: UI hides the button but the API accepts the call; client-side feature flag relied on for security; usage limits enforced client-side only

Role Gating Checklist

For every admin-only feature:

  • Sign in as basic user
  • Try the admin URL directly
  • Try every admin API endpoint (read AND write)
  • Try every field that admins can edit on shared resources (impersonation, role changes, billing)
  • Expected: server enforces; client UI hiding is defense-in-depth, not the gate
  • Common bugs: if (user.role === 'admin') check on the client only; API trusts a client-provided role field; admin features hidden by display:none but rendered in DOM

Tenant Isolation Checklist

For every tenant-scoped resource type:

  • Create resource X in Tenant 1 as User A; capture its ID
  • Switch to User B in Tenant 2
  • Try to GET, PUT, PATCH, DELETE that ID directly
  • Try via the URL bar AND via the API
  • Try with both /tenants/1/resources/X and /resources/X (some APIs accept either)
  • Expected: 404 (preferred — doesn't leak existence) or 403
  • Common bugs: API trusts URL-path tenant ID without verifying user belongs to it; database query joins on user but not tenant; "shared" endpoints (e.g., search) leak across tenants
  • IDs that are guessable (sequential integers) make this worse — note the ID format

Direct-API Bypass Checklist

Open devtools console and run fetch against:

  • Every mutating endpoint with no Cookie / Authorization header
  • Every endpoint with the Cookie of a different user
  • Every endpoint with a foreign tenant's resource ID
  • Every GraphQL query with an introspection request (should be disabled in production)
  • Every endpoint with malformed JSON, oversize payloads, unexpected types
  • Capture the response code and body

This bypass is important because the UI may enforce gates that the API does not. The API is the security boundary; the UI is convenience.

Session Lifecycle Checklist

  • Logout: server-side session is invalidated (subsequent request with the old cookie returns 401, NOT the cached page)
  • Back-button after logout: pages that show protected content should not be served from bfcache
  • Idle timeout: session expires after the configured interval; expired session redirects to login on next protected request
  • Concurrent sessions: signing in from device 2 either keeps device 1 active or revokes it — match the documented behavior
  • Refresh-token rotation: if refresh tokens are used, the old refresh token is invalidated when a new one is issued
  • OAuth state: state parameter is validated on callback; PKCE is enforced for public clients
  • Password change: existing sessions on other devices are invalidated (if that's the documented behavior)

Mutation Protection Checklist

For every mutating endpoint (POST / PUT / PATCH / DELETE):

  • CSRF protection: SameSite=Lax/Strict on session cookie OR explicit CSRF token in header / body
  • Try a cross-origin request from a different origin — confirm it's rejected
  • Try replaying a captured mutation request — confirm idempotency keys or nonces if applicable
  • Try a captured mutation with an old user's session — confirm token is invalidated post-logout

UI Disclosure Checklist

Even when gating works server-side, the UI can leak:

  • Error messages that confirm a resource exists ("You don't have access to project 'Project Alpha'")
  • Autocomplete / search results across tenants
  • URL redirect targets that reveal an entity name
  • 404 pages that include the requested path verbatim
  • Open Graph / Twitter Card meta tags rendered before the gate fires
  • Inviting a user by email reveals if that email already has an account

Prefer: 404 over 403 when "exists but you can't see it" is itself sensitive; generic copy that doesn't echo the resource name.

Multi-Step Flow Auth Checklist

For wizards, checkouts, onboarding:

  • Start step 1 as User A
  • Navigate to step 3 URL directly without completing step 2
  • Sign in as User B mid-flow with User A's draft IDs
  • Refresh between steps
  • Open the same step in two tabs

Verify each step re-validates the actor's right to be on that step.

Browser MCP-Specific Tactics

  • Use multiple browser contexts (browser.newContext() in Playwright) to simulate different users in parallel without juggling cookies
  • Capture each user's session cookie / JWT for direct-fetch probes
  • Use page.evaluate(() => fetch(...)) to bypass UI and hit the API with the page's session
  • Use request.newContext() with no cookie to probe APIs as fully anonymous
  • Snapshot localStorage and sessionStorage on logout to confirm sensitive data was cleared

API Endpoint Enumeration Checklist

Don't only probe routes you see in the UI — enumerate the API:

  • Network panel during a normal session: capture every request
  • OpenAPI / Swagger spec if exposed (/api/docs, /openapi.json)
  • robots.txt and sitemap.xml for hinted endpoints
  • Source maps in production (if not stripped) reveal client-side route definitions
  • JS bundle inspection for embedded API path constants

Calibration

Don't report "the login page is reachable without a session" — it's supposed to be. The audit's value is finding the gates the team thought were closed that are open. Calibrate to data sensitivity: a publicly-displayed username found via a cross-tenant probe is low; a customer's billing detail found via a cross-tenant probe is critical.

  • Severity:

    • Critical — Cross-tenant data leak via any path; admin action executable by non-admin; protected route reachable signed out; paywall bypassable via direct API call; logout doesn't invalidate session server-side
    • High — Premium feature accessible to free users via UI manipulation; admin UI rendered in DOM and hidden by CSS; CSRF protection missing on a mutation; session timeout not enforced
    • Medium — Error message confirms existence of foreign resource; OAuth state not validated; back-button after logout shows cached protected page from bfcache; concurrent sessions not matching documented behavior
    • Low — UI hides a button that the user wouldn't be able to use anyway (still rendered in DOM); 404 message echoes the requested path verbatim
  • Confidence ratings: Confirmed (reproduced the bypass and captured the unauthorized response), Likely (UI suggests a gap and probing strongly indicates the gate is open), Speculative (audit shape suggests probing further is worthwhile).

  • Anti-hallucination guard: Do NOT claim a 200 response is unauthorized access without inspecting the body — some endpoints intentionally return 200 with an empty result for foreign resources. Do not claim a redirect is a bypass without checking whether the protected content was rendered into the initial HTML first. Always verify the actual data leaked, not just the status code.

Output Format

Start with a 5–8 line executive summary: surfaces probed, critical findings, the single highest-severity bypass, the staging build identifier.

  1. User Matrix Used — Roles, tiers, tenants represented in the probe
  2. Unauthenticated Findings — Per route: redirect, leak, status code
  3. Tier Bypass Findings — Per premium feature: UI gate, API gate, result
  4. Role Bypass Findings — Per admin feature: UI gate, API gate, result
  5. Tenant Isolation Findings — Per resource type: cross-tenant probe outcome
  6. Direct-API Findings — Endpoints where the API is more permissive than the UI
  7. Session Lifecycle Findings — Logout, timeout, refresh, OAuth state
  8. Mutation Protection Findings — CSRF, replay, cross-origin
  9. UI Disclosure Findings — Information leaks in error messages, meta tags, redirects
  10. Multi-Step Flow Findings — Wizard / checkout auth re-validation

Close with a Critical Fix List: every Critical and High finding, with a one-line proposed mitigation and the file or middleware where the fix likely lives.

Need help applying this to a real product?

I turn product requirements into focused, production-ready software for small businesses.