From 855d6b1a228b8d7a1c48b819557ff089a8627275 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:06:16 +0200 Subject: [PATCH] Harden url validation in logo endpoint --- apps/api/src/app/logo/get-logo.dto.ts | 9 +++++++++ apps/api/src/app/logo/logo.controller.ts | 3 ++- apps/api/src/app/logo/logo.service.ts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 apps/api/src/app/logo/get-logo.dto.ts diff --git a/apps/api/src/app/logo/get-logo.dto.ts b/apps/api/src/app/logo/get-logo.dto.ts new file mode 100644 index 000000000..e19753157 --- /dev/null +++ b/apps/api/src/app/logo/get-logo.dto.ts @@ -0,0 +1,9 @@ +import { IsUrl } from 'class-validator'; + +export class GetLogoDto { + @IsUrl({ + protocols: ['http', 'https'], + require_protocol: true + }) + url: string; +} diff --git a/apps/api/src/app/logo/logo.controller.ts b/apps/api/src/app/logo/logo.controller.ts index fdbe430c9..47bd1fc75 100644 --- a/apps/api/src/app/logo/logo.controller.ts +++ b/apps/api/src/app/logo/logo.controller.ts @@ -12,6 +12,7 @@ import { import { DataSource } from '@prisma/client'; import { Response } from 'express'; +import { GetLogoDto } from './get-logo.dto'; import { LogoService } from './logo.service'; @Controller('logo') @@ -41,7 +42,7 @@ export class LogoController { @Get() public async getLogoByUrl( - @Query('url') url: string, + @Query() { url }: GetLogoDto, @Res() response: Response ) { try { diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts index 551d62438..ab8007041 100644 --- a/apps/api/src/app/logo/logo.service.ts +++ b/apps/api/src/app/logo/logo.service.ts @@ -47,7 +47,7 @@ export class LogoService { private async getBuffer(aUrl: string) { const blob = await this.fetchService .fetch( - `https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`, + `https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${encodeURIComponent(aUrl)}&size=64`, { headers: { 'User-Agent': 'request' }, signal: AbortSignal.timeout(