Stop Leaking Your Admin Login URL in Redirects and Errors
Why redirecting unauthenticated admin traffic to your login page hands attackers the map, and how to return a clean 404 instead.
There is a quiet vulnerability in a huge number of otherwise careful applications, and it ships as a feature. An unauthenticated user hits /admin, and the app helpfully redirects them to the login page. Convenient for your team. Also a gift to an attacker, because that redirect just confirmed three things: an admin area exists here, it lives behind authentication, and the login form is at this exact URL. You have handed over the map to the one door you most wanted to keep hidden.
To stop leaking your admin login URL, never redirect an unauthenticated request from an admin path to the login page. Return a clean 404 or redirect to the homepage instead, keep the login form at an obscure non-standard path, and make admin error messages generic so they reveal nothing about where the door is.
The fix is to stop being helpful to people who have no business at that door. An unauthenticated request to an admin path should not learn that the path is special, should not be pointed at the login form, and ideally should not be able to tell the difference between your admin area and a URL that does not exist. Here is how to build that, and why the convenient version is worse than it looks.
What the redirect actually tells an attacker
Reconnaissance is the first phase of any serious attack, and it is mostly about reducing uncertainty. An attacker scanning your site does not know where your sensitive surfaces are. They guess common paths and watch how the server responds, and the responses leak structure.
A redirect from /admin to /login answers several of their questions at once. The 302 itself says the path is handled and meaningful. The destination says authentication guards it and reveals the login URL. If the login URL is a predictable standard like /admin/login, you have also confirmed your stack and given them a precise target for credential stuffing, default-credential attempts, and brute force. Every one of those follow-on attacks needs to know where the login form is, and your redirect just told them.
Compare that to a clean 404. The attacker probes /admin, gets "not found," and learns nothing. They cannot distinguish your admin area from the thousands of random paths that also return 404. The uncertainty stays high, the reconnaissance comes up empty, and the attacker moves on to a softer target. That is the entire goal: make the admin surface indistinguishable from nonexistent to anyone who is not already authenticated.
Redirect unauthenticated admin traffic to nothing useful
The rule is simple to state. An unauthenticated request to any /admin/* path should redirect to your homepage or return an HTTP 404, and it should never redirect to a login page, never name the login URL in a Location header, and never hint at the login path in an error message or client-side code.
Both options work, and the same instinct that hides the path is what makes an instant security scan worth running against your own site, since it probes exactly the responses an attacker would. A redirect to / treats the unauthenticated visitor as if they wandered somewhere they do not belong and sends them back to the front of the house, revealing nothing about what lives behind the door. A 404 is even quieter, asserting the path does not exist at all. The point either way is that the response carries no information about the existence, purpose, or location of your admin login.
The login page itself lives at an obscured path, something not guessable like /admin/login, discoverable only by someone who already knows to navigate directly to it. Your team knows the URL; a scanner does not find it by guessing the obvious. And that path never appears in any redirect, because the whole value of obscuring it evaporates the moment a redirect prints it in a Location header for anyone who probes /admin.
The client side has to honor the same rule. A common leak is server-side middleware that returns a clean 404, paired with a client component that, on a failed session check, calls router.push('/admin/login') and re-exposes the path in the browser. Both layers have to send the unauthenticated user somewhere neutral. If the server says "404" but the client says "go to the secret login," the client just undid the protection.
Generic errors everywhere
Redirects are not the only thing that leaks. Error messages from admin APIs leak constantly when they are too specific. "Admin authentication required" tells the attacker there is an admin tier. "Invalid admin token" confirms the token mechanism. "Redirecting to admin login" names the destination.
Every error from a protected admin endpoint should be generic. "Authentication required." "Invalid or expired token." Nothing that hints at admin paths, login URLs, or the auth mechanism behind them. The error an unauthorized request gets should be the same flat, uninformative response whether it hit a real admin endpoint or a path that does not exist. This is the same leak-nothing discipline behind preventing user enumeration in your login and reset flows, where a too-specific message hands the attacker a roster of real accounts. The attacker reading your error responses should come away knowing nothing they did not already know.
This discipline, treating every response to an unauthorized request as a potential information leak, is part of the security baseline we hold across the web applications we build, and it is exactly the kind of issue a focused security audit catches that functional testing never will, because the app works perfectly while quietly broadcasting its own structure. When a leak does slip through, audit logs that actually help after a breach are what let you reconstruct what an attacker found before they found it.
The middleware details that trip people up
If you are protecting admin routes with middleware, two specifics matter enough to call out, because both have bitten real applications.
First, the matcher. In some framework versions, a middleware matcher for /admin/:path* does not match the bare /admin path, only its children. So /admin/users is protected and /admin itself sails through unguarded. Include both the bare path and the wildcard explicitly in your matcher so there is no gap at the root of the admin tree.
Second, do not let middleware be the only thing standing between an attacker and your admin data. The security headers that close off other edge-level tricks are worth shipping alongside this, and the security headers every Next.js app should ship covers that baseline. Next.js shipped a critical authorization-bypass vulnerability, CVE-2025-29927, with a CVSS score of 9.1, that let attackers skip middleware checks entirely by setting an internal x-middleware-subrequest header. It affected a wide range of versions before the patched 12.3.5, 13.5.9, 14.2.25, and 15.2.3 releases. The lesson is not "do not use middleware." It is that middleware is a layer, not a guarantee. Verify authorization again at the data-access layer, in the API route or server action that actually reads the sensitive data, so that bypassing the edge check does not bypass the protection. Keep your framework patched, and never make the outermost check the only check.
Keep the surface off the maps too
Two more places quietly advertise your admin area. Your robots.txt should Disallow: /admin and Disallow: /api/ to keep crawlers out, but it must never list your secret login path, because writing Disallow: /your-secret-login in a public file is the most direct way imaginable to announce that the path exists and matters. Disallow the obvious admin prefix; say nothing about the obscured login.
And both the admin layout and the login page should export metadata telling search engines not to index or follow them, so a leaked link or a misconfiguration does not put your login form into a search result where anyone can find it. The goal across all of these is consistency: every public-facing signal, the redirect, the error, the robots file, the index directives, agrees that there is nothing here worth looking at.
The standard, stated plainly
An attacker who probes your admin surface should walk away with exactly as much information as they started with: none. Unauthenticated requests to admin paths return a 404 or bounce to the homepage, never to a named login. The login form sits at an obscured path that no redirect ever reveals. Error messages are generic. The robots file hides the prefix without naming the secret. Authorization is checked again at the data layer, not just at the edge, so a middleware bypass does not become a breach.
This costs almost nothing to build and it changes the economics of attacking you. A site that helpfully redirects to its login page is doing the attacker's reconnaissance for them. A site that returns a clean 404 makes them work for every scrap of structure, and most of them will simply go find an easier target. The convenient redirect feels like good UX. For the people who should never reach that door, it is the opposite of security.






