Unrestricted Resource Consumption

Unrestricted Resource Consumption in NestJS [CVE-2024-29409]

[Fixed month year] Updated CVE-2024-29409

Overview

CVE-2024-29409 describes a file upload vulnerability in NestJS v10.3.2 where an attacker can cause arbitrary code execution by manipulating the Content-Type header. This is categorized under CWE-94 Code Injection. In practice, server-side code that branches behavior based on untrusted Content-Type values can end up evaluating or loading payloads embedded in uploaded content. Such flawed handling can also lead to resource abuse as malicious payloads trigger heavy processing, escalating into Denial of Service or broader resource exhaustion. The combination of code execution risk and potential DoS makes this a notable Unrestricted Resource Consumption scenario when attackers leverage file uploads to drive costly operations or unsafe evaluation paths.

Affected Versions

NestJS v10.3.2

Code Fix Example

NestJS API Security Remediation
Vulnerable pattern (do not rely on Content-Type to drive processing and may eval content):

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async upload(@UploadedFile() file: Express.Multer.File) {
    // Vulnerable: processing based on MIME type header and potentially using eval on uploaded content
    if (typeof file.mimetype === 'string' && file.mimetype.includes('javascript')) {
      // Dangerous: executing uploaded content
      // @ts-ignore
      eval(file.buffer.toString('utf8'));
    }
    return { size: file.size };
  }
}

Fixed pattern (avoid Content-Type driven logic, enforce strict file validation, and avoid eval):

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import path from 'path';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('file', {
    storage: diskStorage({
      destination: './uploads',
      filename: (req, file, cb) => {
        const safeName = Date.now() + '-' + file.originalname.replace(/[^a-z0-9.-_]/gi, '_');
        cb(null, safeName);
      }
    }),
    limits: { fileSize: 2 * 1024 * 1024 }, // 2 MB limit to reduce DoS risk
    fileFilter: (req, file, cb) => {
      // Do not rely on Content-Type header; validate by actual mime type and extension where applicable
      const allowed = ['image/png', 'image/jpeg', 'application/pdf'];
      if (allowed.includes(file.mimetype)) {
        cb(null, true);
      } else {
        cb(new Error('Unsupported file type'), false);
      }
    }
  }))
  upload(@UploadedFile() file: Express.Multer.File) {
    // Safe handling: no dynamic code execution, just store or hand off to a trusted processor
    return { filename: file.filename, size: file.size };
  }
}

CVE References

Choose which optional cookies to allow. You can change this any time.