Skip to content

Broken access control — dashboard role checks trust a client-editable cookie #1

Description

@AmirhosseinDehghanazar

Hey! I was just randomly browsing through public repos and came across this project — really nice work overall, the UI and structure look solid. While I was looking around I noticed something in the auth/role-checking logic that I thought was worth flagging, since it could be a real security issue if it's not already handled elsewhere in your backend. Hope this is helpful and not intrusive — feel free to close this if it's already on your radar!

What I noticed

In src/proxy.ts, access to the role-specific dashboard routes (/dashboard/admin, /dashboard/seller, /dashboard/buyer) is decided entirely by reading a userRole cookie:

const role = request.cookies.get("userRole")?.value;
...
if (path.startsWith("/dashboard/admin") && role !== "admin") {
  return NextResponse.redirect(new URL("/dashboard", request.url));
}

The same pattern shows up again in the actual page components (e.g. dashboard/admin/estate-management/page.tsx, dashboard/seller/page.tsx, dashboard/layout.tsx) — they all call getServerSideCookie("userRole") and use that value to decide what to render, including which admin-only actions (like deleteHouses) to expose.

I also noticed that alongside the httpOnly server-side cookie, there's a second, plain document.cookie write for the same userRole name in login.tsx and finalStep.tsx (via setClientCookie). That suggests the value is being treated as regular client-side state rather than a trusted credential.

Why this could be a problem

Since nothing re-validates the role against the actual authenticated account (e.g. by decoding it from the signed ServerAccessToken/JWT), any logged-in user could, in theory, open browser DevTools → Application → Cookies and manually change userRole from buyer to admin. That would let them bypass the middleware redirect and reach the admin dashboard UI, including actions like deleting listings.

Whether this turns into a real privilege-escalation issue depends on whether your backend independently re-checks the user's role on each admin API call. If it does, this is "just" a front-end guard that can be bypassed cosmetically. If it doesn't, a regular user could potentially perform admin-only actions.

Suggestion

Derive the role from the verified ServerAccessToken (JWT) on every protected request — both in the middleware and in each server component/route — instead of trusting the plaintext userRole cookie value. It'd also be worth dropping the client-side setClientCookie("userRole", ...) call, since the role really shouldn't be something JS ever needs to read/write directly.

Thanks for the project, and again — hope this is useful! Happy to clarify anything if needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions