Skip to content

Secure file uploads in Fastify

Fastify is a good fit for upload security because you can make the decision in a preHandler before the main route runs.

If you want the wider Node.js context behind that pattern, read Secure file uploads in Node.js: Beyond Extension and MIME Checks.

Terminal window
npm install pompelmi @pompelmi/fastify-plugin fastify @fastify/multipart
import Fastify from 'fastify';
import multipart from '@fastify/multipart';
import { createUploadGuard } from '@pompelmi/fastify-plugin';
import {
CommonHeuristicsScanner,
composeScanners,
createZipBombGuard,
} from 'pompelmi';
const app = Fastify({ logger: true });
await app.register(multipart);
const scanner = composeScanners(
[
['zipGuard', createZipBombGuard()],
['heuristics', CommonHeuristicsScanner],
],
{ stopOn: 'suspicious' }
);
app.post(
'/upload',
{
preHandler: createUploadGuard({
scanner,
includeExtensions: ['pdf', 'png', 'jpg', 'jpeg', 'zip'],
allowedMimeTypes: [
'application/pdf',
'image/png',
'image/jpeg',
'application/zip',
],
maxFileSizeBytes: 10 * 1024 * 1024,
failClosed: true,
stopOn: 'suspicious',
}),
},
async (request) => {
return { ok: true, scan: (request as any).pompelmi };
}
);
  • It rejects blocked uploads before the route body runs.
  • It fits the Fastify lifecycle cleanly.
  • It lets you reuse the same scanner composition you use in Express or Next.js.
  • Keep multipart limits aligned with the guard limits.
  • Use route-specific allowlists instead of one global list.
  • Log blocked verdicts and scanner errors as security-relevant events.