Skip to content
Closed
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ src/components/SpecEditorControl/Untitled-1.json
tsconfig.tsbuildinfo

# ignore middleware for now, as it is and instead, during build, rename
# clerk.middleware.js to clerk.middleware.js
# middleware.clerk.ts to middleware.ts
# middleware.ts

.vercel
Expand All @@ -56,4 +56,6 @@ tsconfig.tsbuildinfo

.envrc
default.nix
.claude
.claude
.playwright-mcp/
*.png
38 changes: 38 additions & 0 deletions middleware.basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

const publicPaths = ["/login", "/api/", "/registration"];

function isPublicPath(pathname: string): boolean {
return publicPaths.some((p) => pathname.startsWith(p));
Comment on lines +6 to +7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Public-path matching is overly broad.

On Line 7, startsWith("/login") and startsWith("/registration") also match paths like /login-anything, which can unintentionally expand unauthenticated surface area.

✅ Safer matcher
 function isPublicPath(pathname: string): boolean {
-  return publicPaths.some((p) => pathname.startsWith(p));
+  return (
+    pathname === "/login" ||
+    pathname === "/registration" ||
+    pathname.startsWith("/api/")
+  );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function isPublicPath(pathname: string): boolean {
return publicPaths.some((p) => pathname.startsWith(p));
function isPublicPath(pathname: string): boolean {
return (
pathname === "/login" ||
pathname === "/registration" ||
pathname.startsWith("/api/")
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware.basic.ts` around lines 6 - 7, The public-path matcher in
isPublicPath is too permissive (e.g., startsWith("/login") matches
"/login-anything"); update isPublicPath to only allow exact matches or proper
path segment prefixes: for each entry in publicPaths (used in isPublicPath)
return true if pathname === p or pathname.startsWith(p + "/") (and handle root
"/" appropriately), ensuring entries like "/login" only match "/login" or
"/login/..." but not "/login-anything".

}

export default function basicMiddleware(request: NextRequest) {
const { pathname } = request.nextUrl;

if (isPublicPath(pathname)) {
return NextResponse.next();
}

const token = request.nextUrl.searchParams.get("token");
if (token) {
return NextResponse.next();
}
Comment on lines +17 to +20

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unvalidated token query param creates an auth bypass.

On Line 17–20, any non-empty ?token= skips authentication for protected pages. This is effectively unauthenticated access unless the token is validated server-side in middleware.

🔐 Suggested hardening
-  const token = request.nextUrl.searchParams.get("token");
-  if (token) {
-    return NextResponse.next();
-  }
+  // Do not bypass auth solely on token presence.
+  // If token-based login is required, validate token cryptographically here
+  // and only for explicit callback routes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware.basic.ts` around lines 17 - 20, The middleware currently treats
any non-empty query param returned by request.nextUrl.searchParams.get("token")
as authenticated and immediately returns NextResponse.next(), which allows auth
bypass; instead, in the middleware function validate the token value server-side
(e.g., verify JWT signature/expiry or compare against a secure server-side
secret) before allowing access, only call NextResponse.next() when verification
succeeds (otherwise return a redirect/NextResponse.rewrite or a 401/403
Response), and update logic around the token variable and NextResponse.next() so
an empty or invalid token does not grant access.


const hasSession =
request.cookies.has("ory_kratos_session") ||
request.cookies.has("authorization");

if (!hasSession) {
const returnTo = encodeURIComponent(request.url);
return NextResponse.redirect(
new URL(`/login?return_to=${returnTo}`, request.url)
);
}

return NextResponse.next();
}

export const config = {
matcher: ["/((?!.*\\..*|_next).*)"]
};
File renamed without changes.
File renamed without changes.
Loading
Loading