Secure file uploads in NestJS
This is the shortest NestJS path when you want upload scanning to fit into modules, interceptors, and controller decorators.
For the broader upload-boundary model that this controller flow fits into, see Secure file uploads in Node.js: Beyond Extension and MIME Checks.
Install
Section titled “Install”npm install pompelmi @pompelmi/nestjsIf you use FileInterceptor() as shown below, make sure your Nest app also has @nestjs/platform-express and multer.
Register the module
Section titled “Register the module”import { Module } from '@nestjs/common';import { PompelmiModule } from '@pompelmi/nestjs';import { CommonHeuristicsScanner, composeScanners, createZipBombGuard,} from 'pompelmi';
const scanner = composeScanners( [ ['zipGuard', createZipBombGuard()], ['heuristics', CommonHeuristicsScanner], ], { stopOn: 'suspicious' });
@Module({ imports: [PompelmiModule.forRoot({ scanner })],})export class AppModule {}Protect an upload controller
Section titled “Protect an upload controller”import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';import { FileInterceptor } from '@nestjs/platform-express';import { PompelmiInterceptor } from '@pompelmi/nestjs';import { memoryStorage } from 'multer';
@Controller('upload')export class UploadController { @Post() @UseInterceptors( FileInterceptor('file', { storage: memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 }, }), PompelmiInterceptor ) async upload(@UploadedFile() file: Express.Multer.File) { return { ok: true, file: file.originalname }; }}Important behavior
Section titled “Important behavior”PompelmiInterceptorrequiresmemoryStorage()so the bytes are available before persistence.- The current interceptor blocks
maliciousuploads and logssuspiciousones. If you want custom quarantine behavior forsuspicious, injectPompelmiServiceand handle thePompelmiScanReportdirectly. - Keep object storage or database writes outside the interceptor path until you have the verdict you want.