Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## 2025-05-23 - [Critical Security Learning - Sentinel Init]
**Vulnerability:** Initial scan revealed minor issues but solid foundation.
**Learning:** Project uses Supabase RLS and `withSecurity` middleware.
**Prevention:** Maintain patterns.
4 changes: 2 additions & 2 deletions app/api/notes/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
import { withSecurity, SECURITY_PRESETS } from '@/lib/security-middleware';
import { formatValidationError, noteDeleteSchema, noteInsertSchema } from '@/lib/validation';
import { formatValidationError, noteDeleteSchema, noteInsertSchema, youtubeIdSchema } from '@/lib/validation';
import { z } from 'zod';

const getNotesQuerySchema = z.object({
youtubeId: z.string()
youtubeId: youtubeIdSchema
});

interface NoteRow {
Expand Down
18 changes: 17 additions & 1 deletion app/api/transcript/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import { withSecurity, SECURITY_PRESETS } from '@/lib/security-middleware';
import { shouldUseMockData, getMockTranscript } from '@/lib/mock-data';
import { mergeTranscriptSegmentsIntoSentences } from '@/lib/transcript-sentence-merger';
import { NO_CREDITS_USED_MESSAGE } from '@/lib/no-credits-message';
import { z } from 'zod';

// Strict validation for language code (ISO 639-1)
// Only allow 2-10 alphanumeric characters and dashes
const langSchema = z.string()
.min(2)
.max(10)
.regex(/^[a-zA-Z0-9-]+$/)
.optional();

function respondWithNoCredits(
payload: Record<string, unknown>,
Expand Down Expand Up @@ -33,6 +42,13 @@ async function handler(request: NextRequest) {
return respondWithNoCredits({ error: 'Invalid YouTube URL' }, 400);
}

// Validate lang if provided
try {
langSchema.parse(lang);
} catch {
return respondWithNoCredits({ error: 'Invalid language code format' }, 400);
}

if (shouldUseMockData()) {
console.log(
'[TRANSCRIPT] Using mock data (NEXT_PUBLIC_USE_MOCK_DATA=true)'
Expand Down Expand Up @@ -210,7 +226,7 @@ async function handler(request: NextRequest) {
}

const rawSegments = Array.isArray(transcriptSegments)
? transcriptSegments.map((item, idx) => {
? transcriptSegments.map((item) => {
const transformed = {
text: item.text || item.content || '',
// Convert milliseconds to seconds for offset/start
Expand Down