fix: scheme-validate crawler source_url before rendering as a link

Harvested source_url (external content) rendered as an admin <a href> without
scheme validation — a javascript:/data: link would execute on click (audit M2).
safeExternalHref() gates to http(s); CrawlerHistoryTable/DeadJobsTable fall back
to plain text otherwise. Tested in safeHref.test.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-13 21:16:08 +02:00
parent f2c9cfe162
commit 958d5bd713
7 changed files with 71 additions and 9 deletions

View File

@@ -0,0 +1,21 @@
/**
* Return `url` only if it is a well-formed `http(s)` URL that is safe to place
* in an `href`, otherwise `null`.
*
* Crawler `source_url` values are external/untrusted content harvested from
* scraped source sites. Svelte does NOT sanitize URL schemes in `href`
* bindings, so a harvested `javascript:`/`data:`/`vbscript:` link would execute
* (or phish) in the admin origin on click. Callers render the title as plain
* text when this returns `null`.
*/
export function safeExternalHref(url: string | null | undefined): string | null {
if (!url) return null;
let parsed: URL;
try {
parsed = new URL(url);
} catch {
// Relative or malformed — not a safe external link.
return null;
}
return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? url : null;
}