Summary
Two security issues in the Next.js BFF API layer:
1. Unauthenticated LiveKit JWT Generation (HIGH)
The /api/livekit endpoint generates LiveKit room JWT tokens with full admin privileges for any unauthenticated caller.
File: apps/web/app/api/livekit/route.ts
The endpoint accepts roomName and username query parameters and returns a JWT token with extensive privileges including roomAdmin: true, roomRecord: true, roomCreate: true, roomList: true.
No authentication check is performed - compare with the Jitsi Meet JWT endpoint (/api/auth/meet/jwt/route.ts) which correctly uses `authenticatedGuard`:
```typescript
// SECURE - Jitsi Meet JWT (route.ts line 45)
const { $res, user } = await authenticatedGuard(req, res);
// VULNERABLE - LiveKit JWT (route.ts line 4)
export async function GET(req: NextRequest) {
const room = req.nextUrl.searchParams.get("roomName");
const username = req.nextUrl.searchParams.get("username");
// NO authenticatedGuard call
const at = new AccessToken(apiKey, apiSecret, { identity: username, ttl: '1h' });
at.addGrant({ room, roomJoin: true, roomAdmin: true, roomRecord: true, roomList: true, ... });
}
```
Impact: Any anonymous internet user can join, record, and administrate any LiveKit room.
2. Missing authenticatedGuard on Timesheet Reporting Endpoints (MEDIUM)
Two timesheet reporting routes are missing the authenticatedGuard call that adjacent sibling endpoints have:
apps/web/app/api/timesheet/activity/report/route.ts - missing guard
apps/web/app/api/timesheet/time-log/report/daily/route.ts - missing guard
Compare with the secure siblings:
apps/web/app/api/timesheet/statistics/counts/route.ts - has authenticatedGuard ✅
apps/web/app/api/timesheet/time-log/report/daily-chart/route.ts - has authenticatedGuard ✅
Suggested Fix
Add authenticatedGuard to the LiveKit endpoint:
```typescript
import { authenticatedGuard } from '@/core/services/server/guards/authenticated-guard-app';
export async function GET(req: NextRequest) {
const res = new NextResponse();
const { $res, user, access_token } = await authenticatedGuard(req, res);
if (!user) return $res('Unauthorized');
// ... existing token generation, using user identity instead of query param
}
```
Discovery
Found through automated security research comparing auth patterns across API route handlers.
Summary
Two security issues in the Next.js BFF API layer:
1. Unauthenticated LiveKit JWT Generation (HIGH)
The
/api/livekitendpoint generates LiveKit room JWT tokens with full admin privileges for any unauthenticated caller.File:
apps/web/app/api/livekit/route.tsThe endpoint accepts
roomNameandusernamequery parameters and returns a JWT token with extensive privileges includingroomAdmin: true,roomRecord: true,roomCreate: true,roomList: true.No authentication check is performed - compare with the Jitsi Meet JWT endpoint (
/api/auth/meet/jwt/route.ts) which correctly uses `authenticatedGuard`:```typescript
// SECURE - Jitsi Meet JWT (route.ts line 45)
const { $res, user } = await authenticatedGuard(req, res);
// VULNERABLE - LiveKit JWT (route.ts line 4)
export async function GET(req: NextRequest) {
const room = req.nextUrl.searchParams.get("roomName");
const username = req.nextUrl.searchParams.get("username");
// NO authenticatedGuard call
const at = new AccessToken(apiKey, apiSecret, { identity: username, ttl: '1h' });
at.addGrant({ room, roomJoin: true, roomAdmin: true, roomRecord: true, roomList: true, ... });
}
```
Impact: Any anonymous internet user can join, record, and administrate any LiveKit room.
2. Missing authenticatedGuard on Timesheet Reporting Endpoints (MEDIUM)
Two timesheet reporting routes are missing the
authenticatedGuardcall that adjacent sibling endpoints have:apps/web/app/api/timesheet/activity/report/route.ts- missing guardapps/web/app/api/timesheet/time-log/report/daily/route.ts- missing guardCompare with the secure siblings:
apps/web/app/api/timesheet/statistics/counts/route.ts- hasauthenticatedGuard✅apps/web/app/api/timesheet/time-log/report/daily-chart/route.ts- hasauthenticatedGuard✅Suggested Fix
Add
authenticatedGuardto the LiveKit endpoint:```typescript
import { authenticatedGuard } from '@/core/services/server/guards/authenticated-guard-app';
export async function GET(req: NextRequest) {
const res = new NextResponse();
const { $res, user, access_token } = await authenticatedGuard(req, res);
if (!user) return $res('Unauthorized');
}
```
Discovery
Found through automated security research comparing auth patterns across API route handlers.