feat(api): capture POST + upload + SSRF-safe URL fetch

safe_fetch.js validates URLs before fetch: rejects non-http(s), literal
or DNS-resolved loopback / RFC1918 / link-local / CGNAT / metadata
addresses; follows redirects manually with the same checks on each hop.
Test fixtures gate the check with VOID_INGEST_ALLOW_PRIVATE for offline
fixtures that hit 127.0.0.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-01 03:42:54 +10:00
parent eceebd2947
commit afc20712cb
6 changed files with 278 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ import { router as pendingChangesRouter } from './routes/pending_changes.js';
import { router as auditRouter } from './routes/audit.js';
import { router as searchRouter } from './routes/search.js';
import { router as jobsRouter } from './routes/jobs.js';
import { router as captureRouter } from './routes/capture.js';
export function mountApi(app) {
const api = Router();
@@ -49,6 +50,7 @@ export function mountApi(app) {
api.use('/audit', auditRouter);
api.use('/search', searchRouter);
api.use('/jobs', jobsRouter);
api.use('/capture', captureRouter);
api.use('/:entity_type/:entity_id/tags', tagsByEntityRouter);
api.use((_req, _res, next) => next(new NotFoundError('route not found')));