project-nomad/admin/app/controllers/collection_updates_controller.ts
Chris Sherwood 75106a8f61 fix(security): path traversal and SSRF protections from pre-launch audit
Fixes 4 high-severity findings from a comprehensive security audit:

1. Path traversal on ZIM file delete — resolve()+startsWith() containment
2. Path traversal on Map file delete — same pattern
3. Path traversal on docs read — same pattern (already used in rag_service)
4. SSRF on download endpoints — block private/internal IPs, require TLD

Also adds assertNotPrivateUrl() to content update endpoints.

Full audit report attached as admin/docs/security-audit-v1.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:08:09 -07:00

31 lines
1.0 KiB
TypeScript

import { CollectionUpdateService } from '#services/collection_update_service'
import {
assertNotPrivateUrl,
applyContentUpdateValidator,
applyAllContentUpdatesValidator,
} from '#validators/common'
import type { HttpContext } from '@adonisjs/core/http'
export default class CollectionUpdatesController {
async checkForUpdates({}: HttpContext) {
const service = new CollectionUpdateService()
return await service.checkForUpdates()
}
async applyUpdate({ request }: HttpContext) {
const update = await request.validateUsing(applyContentUpdateValidator)
assertNotPrivateUrl(update.download_url)
const service = new CollectionUpdateService()
return await service.applyUpdate(update)
}
async applyAllUpdates({ request }: HttpContext) {
const { updates } = await request.validateUsing(applyAllContentUpdatesValidator)
for (const update of updates) {
assertNotPrivateUrl(update.download_url)
}
const service = new CollectionUpdateService()
return await service.applyAllUpdates(updates)
}
}