Harden admin visibility probe against Authelia LAN bypass

Require GET /admin and /api/v1/admin/me so anonymous internal
clients do not see the Admin link.
This commit is contained in:
2026-07-24 08:59:12 -04:00
parent af5bfc1b75
commit 6340dc5df9
+20 -6
View File
@@ -1,8 +1,11 @@
/**
* Probe Traefik/Authelia protection on /admin.
* Returns true only when a same-origin GET succeeds (HTTP 200),
* meaning the visitor is already authenticated for admin.
* Failures (401/403/302/network) keep the public site admin-free.
* Returns true only when:
* 1) GET /admin succeeds (HTTP 200) — path is allowed through Authelia
* 2) GET /api/v1/admin/me succeeds — Remote-User is present and authorized
*
* (2) matters on LAN where Authelia may bypass auth but still leave no Remote-User,
* so the public site stays admin-free for anonymous visitors.
*/
export async function canAccessAdmin(): Promise<boolean> {
try {
@@ -13,11 +16,22 @@ export async function canAccessAdmin(): Promise<boolean> {
cache: "no-store",
headers: { Accept: "text/html" },
});
// opaqueredirect (0) = browser blocked reading a cross-origin redirect
// 3xx with redirect:manual also means not authorized for the resource
// opaqueredirect = browser blocked reading a cross-origin redirect
if (res.type === "opaqueredirect") return false;
if (res.status >= 300 && res.status < 400) return false;
return res.status === 200;
if (res.status !== 200) return false;
// Confirm real Authelia identity (not just network-level bypass of /admin)
const me = await fetch("/api/v1/admin/me", {
method: "GET",
credentials: "include",
redirect: "manual",
cache: "no-store",
headers: { Accept: "application/json" },
});
if (me.type === "opaqueredirect") return false;
if (me.status >= 300 && me.status < 400) return false;
return me.status === 200;
} catch {
return false;
}