diff --git a/openspec/changes/code-review-fix/tasks.md b/openspec/changes/code-review-fix/tasks.md index f2a6df8..6da5d84 100644 --- a/openspec/changes/code-review-fix/tasks.md +++ b/openspec/changes/code-review-fix/tasks.md @@ -11,7 +11,7 @@ ## 2. Security Critical — Input Validation & CORS -- [ ] 2.1 `[haiku]` Validate `run_id` matches `/^[a-zA-Z0-9_-]+$/` in `src/app/api/training/runs/[run_id]/route.ts` before interpolation +- [x] 2.1 `[haiku]` Validate `run_id` matches `/^[a-zA-Z0-9_-]+$/` in `src/app/api/training/runs/[run_id]/route.ts` before interpolation - [ ] 2.2 `[sonnet]` Validate `run_id` format and use `Path.resolve()` + directory containment check in `services/ml/app/main.py` (model load at line 1203, delete at line 1312) - [ ] 2.3 `[sonnet]` Add file size check (reject >10MB) and row count limit (500,000) to `src/app/api/upload/route.ts` - [ ] 2.4 `[haiku]` Add file type validation (`.csv` extension, text MIME type) to `src/app/api/upload/route.ts` diff --git a/src/app/api/training/runs/[run_id]/route.ts b/src/app/api/training/runs/[run_id]/route.ts index da05d9c..1ac3773 100644 --- a/src/app/api/training/runs/[run_id]/route.ts +++ b/src/app/api/training/runs/[run_id]/route.ts @@ -8,6 +8,16 @@ export async function DELETE( { params }: { params: Promise<{ run_id: string }> } ) { const { run_id } = await params; + + // Validate run_id format before using in interpolation + const RUN_ID_REGEX = /^[a-zA-Z0-9_-]+$/; + if (!RUN_ID_REGEX.test(run_id)) { + return NextResponse.json( + { error: 'Invalid run_id format' }, + { status: 400 } + ); + } + const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), INFERENCE_API_TIMEOUT);