From 77020e742a0d8ba5c5ba48f1f34b244a764a5444 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Wed, 18 Mar 2026 14:15:48 -0400 Subject: [PATCH] fix: validate accept header before returning html (#27019) --- cli/src/utils.ts | 2 +- server/src/services/api.service.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cli/src/utils.ts b/cli/src/utils.ts index 38bd119459..b60f5e3715 100644 --- a/cli/src/utils.ts +++ b/cli/src/utils.ts @@ -81,7 +81,7 @@ export const connect = async (url: string, key: string) => { const [error] = await withError(getMyUser()); if (isHttpError(error)) { - logError(error, 'Failed to connect to server'); + logError(error, `Failed to connect to server ${url}`); process.exit(1); } diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts index ed1b4095d6..1071c75fc7 100644 --- a/server/src/services/api.service.ts +++ b/server/src/services/api.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotAcceptableException } from '@nestjs/common'; import { Interval } from '@nestjs/schedule'; import { NextFunction, Request, Response } from 'express'; import { readFileSync } from 'node:fs'; @@ -72,6 +72,13 @@ export class ApiService { return next(); } + const responseType = request.accepts('text/html'); + if (!responseType) { + throw new NotAcceptableException( + `The route ${request.path} was requested as ${request.header('accept')}, but only returns text/html`, + ); + } + let status = 200; let html = index; @@ -105,7 +112,7 @@ export class ApiService { html = render(index, meta); } - res.status(status).type('text/html').header('Cache-Control', 'no-store').send(html); + res.status(status).type(responseType).header('Cache-Control', 'no-store').send(html); }; } }