SSRF

SSRF in NestJS: CVE-2024-29409 fix [June 2026] [CVE-2024-29409]

[Updated June 2026] Updated CVE-2024-29409

Overview

In the wild, CVE-2024-29409 targeted the NestJS file upload path in v10.3.2, allowing remote code execution by manipulating the Content-Type header during file upload. This is a CWE-94 style risk: untrusted data combined with unsafe code execution can lead to full system compromise. The vulnerability is tied to improper handling of dynamic behavior triggered by request headers, enabling an attacker to cause arbitrary code execution in the server process if the header is used to influence code paths or to eval uploaded content. Such flaws are particularly dangerous in web services that accept user-supplied files and process them without strict validation or isolation. The vulnerability manifests when a handler uses the Content-Type header to decide how to process an uploaded file, potentially invoking dangerous operations such as evaluating the file contents or loading code paths based on header values. An attacker can craft a file and a malicious Content-Type value to trigger code execution in the Node.js process, enabling remote takeover, data exposure, or service disruption. This behavior aligns with CWE-94 (Improper Control of Generation of Code) and is a critical class of risk for file upload endpoints in NestJS apps. Remediation involves removing any reliance on Content-Type to drive executable behavior, validating uploads with strict, server-side checks, and preventing code execution of user-provided content. Use Multer’s fileFilter with a safe allowlist, verify content using a content-detection library (not the header), and store files in a non-executable location with sanitized filenames. Eliminate eval or dynamic requires, and upgrade to patched NestJS versions. Implement defensive tests that simulate malicious headers to ensure uploads do not trigger code execution. Developers should adopt a defense-in-depth approach: separate concerns between file handling and business logic, validate and sanitize all inputs, and monitor for anomalous upload attempts as part of a secure development lifecycle.

Affected Versions

NestJS v10.3.2 (vulnerable); patched or newer releases recommended

Code Fix Example

NestJS API Security Remediation
// Vulnerable pattern
import { Controller, Post, UploadedFile, UseInterceptors, Req } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Request } from 'express';

@Controller('upload')
export class UploadControllerVulnerable {
  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async upload(@UploadedFile() file: Express.Multer.File, @Req() req: Request) {
    // Vulnerable: rely on Content-Type header to decide dangerous behavior
    const contentType = req.headers['content-type'];
    if (contentType === 'application/javascript') {
      const code = file.buffer.toString('utf8');
      // UNSAFE: execute uploaded code
      // eslint-disable-next-line no-eval
      eval(code);
    }
    return { filename: file?.originalname };
  }
}

// Fixed pattern
import { Controller, Post, UploadedFile, UseInterceptors, Req, BadRequestException } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { Request } from 'express';

const ALLOWED_MIME = ['image/png', 'image/jpeg', 'application/pdf'];
function safeFileName(_req, file, cb) {
  const name = (file.originalname || 'file').replace(/[^a-zA-Z0-9_.-]/g, '_');
  cb(null, `${Date.now()}_${name}`);
}

@Controller('upload')
export class UploadControllerFixed {
  @Post()
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: safeFileName,
      }),
      fileFilter: (req, file, cb) => {
        if (ALLOWED_MIME.includes(file.mimetype)) {
          cb(null, true);
        } else {
          cb(new BadRequestException('Unsupported file type'), false);
        }
      },
      limits: { fileSize: 5 * 1024 * 1024 },
    }),
  )
  async upload(@UploadedFile() file: Express.Multer.File, @Req() req: Request) {
    // Safe: never execute uploaded content; just return metadata
    return { filename: file?.filename, mime: file?.mimetype };
  }
}

CVE References

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