From 66b292b11bde3664f05ffb016c8082665d261ded Mon Sep 17 00:00:00 2001 From: Bernd Storath <32197462+kaaax0815@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:55:22 +0200 Subject: [PATCH] improve security (#2661) * disable basic auth when password auth disabled * clarify otl security --- src/server/database/repositories/oneTimeLink/service.ts | 9 +++++++++ src/server/routes/cnf/[oneTimeLink].ts | 7 +++++++ src/server/utils/session.ts | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/src/server/database/repositories/oneTimeLink/service.ts b/src/server/database/repositories/oneTimeLink/service.ts index 49162ac0..68328d13 100644 --- a/src/server/database/repositories/oneTimeLink/service.ts +++ b/src/server/database/repositories/oneTimeLink/service.ts @@ -52,6 +52,10 @@ export class OneTimeLinkService { } generate(id: ID) { + // SECURITY + // This is known to be vulnerable to brute force attacks + // Mitigations: Small Window, One Time Use + // Making it longer defeats the whole purpose const key = `${id}-${Math.floor(Math.random() * 1000)}`; const oneTimeLink = Math.abs(CRC32.str(key)).toString(16); const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString(); @@ -60,6 +64,11 @@ export class OneTimeLinkService { } erase(id: ID) { + // SECURITY + // This is known the extend the Window for brute force attacks + // Reason: Set the expiresAt to 10 seconds in the future to allow a second request to get the otl + // some browser apparently make two requests when downloading a file + // cant find the bug report anymore, maybe this can be removed? const expiresAt = new Date(Date.now() + 10 * 1000).toISOString(); return this.#statements.erase.execute({ id, expiresAt }); } diff --git a/src/server/routes/cnf/[oneTimeLink].ts b/src/server/routes/cnf/[oneTimeLink].ts index bc38d9ea..ecc4273a 100644 --- a/src/server/routes/cnf/[oneTimeLink].ts +++ b/src/server/routes/cnf/[oneTimeLink].ts @@ -14,6 +14,13 @@ export default defineEventHandler(async (event) => { }); } + if (new Date() > new Date(otl.expiresAt)) { + throw createError({ + statusCode: 410, + statusMessage: 'One Time Link has expired', + }); + } + const client = await Database.clients.get(otl.id); if (!client) { throw createError({ diff --git a/src/server/utils/session.ts b/src/server/utils/session.ts index ef48a326..8fd7646f 100644 --- a/src/server/utils/session.ts +++ b/src/server/utils/session.ts @@ -54,6 +54,13 @@ export async function getCurrentUser(event: H3Event) { // Handle if authenticating using Session user = await Database.users.get(session.data.userId); } else if (authorization) { + if (WG_ENV.DISABLE_PASSWORD_AUTH) { + throw createError({ + statusCode: 403, + statusMessage: 'Password authentication is disabled', + }); + } + // Handle if authenticating using Header const [method, value] = authorization.split(' '); // Support Basic Authentication