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:
21
frontend/src/lib/safeHref.ts
Normal file
21
frontend/src/lib/safeHref.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user