From d6b2dd6e6da0d21285b4de33d3ff72743c6b824f Mon Sep 17 00:00:00 2001 From: anupamme Date: Mon, 7 Sep 2026 03:16:14 +0000 Subject: [PATCH] fix: V-001 security vulnerability Automated security fix generated by OrbisAI Security --- telemetry-dashboard/src/index.ts | 16 ++++++++++++++++ telemetry-dashboard/wrangler.jsonc | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/telemetry-dashboard/src/index.ts b/telemetry-dashboard/src/index.ts index 4748a1938..8a3583b8d 100644 --- a/telemetry-dashboard/src/index.ts +++ b/telemetry-dashboard/src/index.ts @@ -157,6 +157,19 @@ async function loginRateLimitOk(env: Env, request: Request): Promise { } } +/** Best-effort abuse cap on the authenticated API surface, keyed by client IP. */ +async function apiRateLimitOk(env: Env, request: Request): Promise { + const key = request.headers.get('cf-connecting-ip') ?? 'unknown'; + try { + const { success } = await env.API_RATE_LIMITER.limit({ key }); + return success; + } catch (err) { + // Fail open: a rate-limiter outage must not take the dashboard down. + console.error(JSON.stringify({ msg: 'api rate limiter unavailable', err: String(err) })); + return true; + } +} + async function handleLoginPage(env: Env, request: Request, url: URL): Promise { const next = safeNextPath(url.searchParams.get('next')); if (await hasValidSession(env, request)) return redirect(next); @@ -260,6 +273,9 @@ export default { if (!isRead) { return json({ error: 'method not allowed' }, { status: 405, headers: { allow: 'GET' } }); } + if (!(await apiRateLimitOk(env, request))) { + return json({ error: 'too many requests' }, { status: 429 }); + } return await apiResponse(env, url); } diff --git a/telemetry-dashboard/wrangler.jsonc b/telemetry-dashboard/wrangler.jsonc index ce554a751..aa8069de2 100644 --- a/telemetry-dashboard/wrangler.jsonc +++ b/telemetry-dashboard/wrangler.jsonc @@ -46,6 +46,11 @@ "name": "LOGIN_RATE_LIMITER", "namespace_id": "2001", "simple": { "limit": 5, "period": 60 } + }, + { + "name": "API_RATE_LIMITER", + "namespace_id": "2002", + "simple": { "limit": 120, "period": 60 } } ] }