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>
22 lines
830 B
TypeScript
22 lines
830 B
TypeScript
/**
|
|
* 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;
|
|
}
|