fix security issues

This commit is contained in:
Gerhard Scheikl
2026-05-09 22:19:25 +02:00
parent c45648832a
commit 3a77bed716
6 changed files with 391 additions and 36 deletions
+21 -8
View File
@@ -11,6 +11,7 @@ import {
DEFAULT_EMAIL_SUBJECT_EN,
} from "./emailTemplates";
import { STORED_LOGO_SENTINEL } from "./logoCache.constants";
import { safeFetch, SafeFetchError, SHOPIFY_CDN_HOSTS } from "./safeFetch.server";
export interface SendInvoiceEmailArgs {
shopDomain: string;
@@ -100,9 +101,15 @@ export async function sendInvoiceEmail(
// Download the PDF (Shopify Files URLs are public CDN URLs).
let pdfBytes: Uint8Array;
try {
const res = await fetch(invoice.pdfUrl);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
pdfBytes = new Uint8Array(await res.arrayBuffer());
const res = await safeFetch(invoice.pdfUrl, {
maxBytes: 25 * 1024 * 1024, // 25 MB — generous; emails impose their own limit later
accept: "application/pdf",
// Invoice PDFs always live on Shopify's Files CDN — anything else is
// suspicious and should be rejected.
allowedHosts: SHOPIFY_CDN_HOSTS,
});
if (res.status < 200 || res.status >= 300) throw new Error(`HTTP ${res.status}`);
pdfBytes = res.bytes;
} catch (err) {
const m = err instanceof Error ? err.message : String(err);
return failLog(args, `Failed to download invoice PDF: ${m}`, invoice.id);
@@ -348,11 +355,17 @@ async function loadInlineLogo(
if (!cached) return null;
return { bytes: new Uint8Array(cached.bytes), contentType: cached.contentType };
}
const res = await fetch(settings.logoUrl);
if (!res.ok) return null;
const ct = res.headers.get("content-type") ?? "image/png";
return { bytes: new Uint8Array(await res.arrayBuffer()), contentType: ct };
} catch {
const res = await safeFetch(settings.logoUrl, {
maxBytes: 5 * 1024 * 1024,
accept: "image/*",
});
if (res.status < 200 || res.status >= 300) return null;
const ct = res.contentType ?? "image/png";
return { bytes: res.bytes, contentType: ct };
} catch (err) {
if (err instanceof SafeFetchError) {
console.warn(`Inline logo fetch refused (${err.code}): ${err.message}`);
}
return null;
}
}