Skip to content

File upload security: no content scanning before storage (MIME spoofing, ZIP bombs, macros) #2169

Description

@SonoTommy

File upload security: no content scanning before storage

Context

This boilerplate ships with a well-structured file upload module supporting local and S3 drivers, including s3-presigned for production. The architecture is correct — the problem is that no step inspects file content before the record is committed to the database.

This means a client can upload:

  • A file with a spoofed MIME type or extension (e.g. a script disguised as avatar.jpg)
  • A ZIP bomb that expands to exhaust resources when later extracted or processed
  • An Office file with embedded macros, or a PDF with embedded JavaScript actions
  • A polyglot file that is valid in multiple formats simultaneously

These bypass the current size and extension checks entirely, because they operate at the byte-content level — not at the filename or client-reported MIME level.

Natural integration point

For the local driver: scan req.file.buffer (already in memory via multer) before writing to disk.

For the s3-presigned driver: scan after the client uploads to the quarantine bucket and before promoting to the production bucket and saving the DB record.

Suggested tool

pompelmi is an MIT-licensed, in-process Node.js scanner with a dedicated NestJS integration package (@pompelmi/nestjs-integration, already listed in awesome-nestjs). Zero external API calls — files never leave the process.

Minimal NestJS guard using the existing module structure:

import { scanBytes, STRICT_PUBLIC_UPLOAD } from 'pompelmi';

// Inside your FilesService, before saving:
const report = await scanBytes(file.buffer, {
  filename: file.originalname,
  mimeType: file.mimetype,
  policy: STRICT_PUBLIC_UPLOAD,
  failClosed: true,
});

if (report.verdict !== 'clean') {
  throw new UnprocessableEntityException({
    status: HttpStatus.UNPROCESSABLE_ENTITY,
    errors: { file: `blocked: ${report.reasons.join(', ')}` },
  });
}

Proposed changes

  1. Add a scan step inside FilesLocalService and FilesS3PresignedService before committing to storage
  2. Add pompelmi to the docs under file-uploading.md as the recommended scanning approach
  3. Optionally: expose scan policy as a config option so teams can tune sensitivity

Happy to submit a PR — let me know which scope works best.


References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions