fix(server): inert proxy responses, API-call header, image-only uploads; origin check by host

From the final review: proxied archived HTML could run on our origin and read a
remembered token; /api/upload accepted any Wayback URL and GIF-prefixed bytes; the
origin check broke behind a TLS proxy; one unreadable snapshot could fail a run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-15 01:49:52 +02:00
1 parent 5084f8c557
commit baa3476b73
16 files changed
+183 -26

No files matched your search

+5 -2
View File
@@ -5,8 +5,11 @@ const NAMED: Readonly<Record<string, string>> = { amp: "&", lt: "<", gt: ">", qu
export function decodeEntities(s: string): string {
return s.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (match, entity: string) => {
const e = entity.toLowerCase();
if (e.startsWith("#x")) return String.fromCodePoint(parseInt(e.slice(2), 16));
if (e.startsWith("#")) return String.fromCodePoint(parseInt(e.slice(1), 10));
if (e.startsWith("#")) {
const code = e.startsWith("#x") ? parseInt(e.slice(2), 16) : parseInt(e.slice(1), 10);
// Malformed pages carry entities like &#99999999;: leave them as written rather than throw.
return Number.isInteger(code) && code >= 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match;
}
return NAMED[e] ?? match;
});
}