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:
1 parent
5084f8c557
commit
baa3476b73
16 files changed
+183
-26
No files matched your search
+5
-2
@@ -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 �: leave them as written rather than throw.
|
||||
return Number.isInteger(code) && code >= 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match;
|
||||
}
|
||||
return NAMED[e] ?? match;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user