diff --git a/e2e/api.spec.ts b/e2e/api.spec.ts index b795283..44da962 100644 --- a/e2e/api.spec.ts +++ b/e2e/api.spec.ts @@ -532,6 +532,19 @@ test("Projektvorlagen: aus Projekt sichern und anwenden", async ({ request, play expect((await request.delete(`/api/templates/${vorlage.id}`)).ok()).toBeTruthy(); }); +test("Der Bildoptimierer ist zu", async ({ playwright }) => { + // /_next/image reicht jedes Bild durch sharp und damit durch libvips, fuer + // das es regelmaessig Schwachstellen gibt. Nebula benutzt next/image + // nirgends – der Endpunkt darf ohne Anmeldung nicht antworten. + const anonym = await playwright.request.newContext({ + baseURL: test.info().project.use.baseURL, + maxRedirects: 0, + }); + const antwort = await anonym.get("/_next/image?url=%2Ficon-192.png&w=64&q=75"); + expect(antwort.status(), "kein 200 ohne Anmeldung").not.toBe(200); + await anonym.dispose(); +}); + test("Export enthaelt keine Geheimnisse, Import beachtet die Strategie", async ({ request }) => { await login(request, ADMIN); diff --git a/next.config.ts b/next.config.ts index 239ce44..aeda258 100644 --- a/next.config.ts +++ b/next.config.ts @@ -9,6 +9,21 @@ const nextConfig: NextConfig = { poweredByHeader: false, // Prisma darf nicht gebundlet werden, sonst findet der Client seine Engine nicht. serverExternalPackages: ["@prisma/client", "prisma"], + images: { + /** + * Der Bildoptimierer ist abgeschaltet. + * + * Nebula benutzt next/image nirgends – die paar Symbole sind SVG und + * PNG in fester Groesse. Der Endpunkt /_next/image waere aber trotzdem + * da, und zwar ohne Anmeldung: die Middleware nimmt ihn aus, weil dort + * sonst nur Rechenzeit verbraucht wuerde. + * + * Er reicht jedes Bild durch sharp und damit durch libvips, fuer das es + * regelmaessig Schwachstellen gibt (aktuell CVE-2026-33327 und drei + * weitere). Eine Angriffsflaeche ohne Gegenwert – also weg damit. + */ + unoptimized: true, + }, }; export default nextConfig; diff --git a/src/middleware.ts b/src/middleware.ts index 320773c..f2cf86f 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -147,7 +147,10 @@ export const config = { * weder CSRF-Pruefung noch Nonce und wuerden nur Rechenzeit kosten. */ { - source: "/((?!_next/static|_next/image|favicon.ico|icon.svg).*)", + // _next/image ist bewusst *nicht* ausgenommen: der Bildoptimierer ist + // abgeschaltet (siehe next.config.ts), und was von ihm uebrig bleibt, + // soll nicht ohne Sitzung erreichbar sein. + source: "/((?!_next/static|favicon.ico|icon.svg).*)", missing: [ { type: "header", key: "next-router-prefetch" }, { type: "header", key: "purpose", value: "prefetch" },