Broken Function Level Authorization

Broken Function Level Authorization in NestJS [Mar 2026] [CVE-2024-29409]

[Mar 2026] Updated CVE-2024-29409

Overview

CVE-2024-29409 describes a file-upload vulnerability in NestJS v10.3.2 (CWE-94) that allowed an attacker to execute arbitrary code via the Content-Type header. In practice, this real-world flaw demonstrates how untrusted input at the file boundary can become a weapon if the server’s processing path uses the header to decide how to handle payloads or to trigger dynamic evaluation. This guide uses that CVE to illustrate the risks and the need for robust function-level authorization and input handling in NestJS applications. From a Broken Function Level Authorization (FFLA) perspective, such flaws highlight how failing to enforce proper authorization on a function that handles untrusted input creates a path for exploitation. An endpoint that accepts uploads without restricting who can call it or without validating the payload can allow attackers to push dangerous content and cause effects beyond mere data leakage, potentially leading to code execution or broader system compromise. Remediation moves beyond generic fixes: enforce function-level authorization using Nest guards and role-based annotations; validate uploads with strict content checks rather than trusting Content-Type headers; avoid any code execution pathways for uploaded data; and keep dependencies up to date with patched releases. The CVE demonstrates why a defense-in-depth approach-guarding, validating, and safely handling uploads-matters for NestJS security. The guidance that follows ties these concepts to concrete NestJS code patterns and a side-by-side remediation example so developers can apply a real fix in their projects.

Affected Versions

NestJS v10.3.2

Code Fix Example

NestJS API Security Remediation
VULNERABLE:
import { Controller, Post, UploadedFile, UseInterceptors, Headers } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { memoryStorage } from 'multer';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('file', { storage: memoryStorage() }))
  upload(@UploadedFile() file: Express.Multer.File, @Headers('content-type') contentType: string) {
    // Vulnerable: relies on untrusted Content-Type header to decide how to process the file
    if (contentType === 'text/javascript') {
      // SECURITY RISK: executing uploaded code
      // @ts-ignore
      eval(file.buffer.toString('utf8'));
    }
  }
}

FIX:
import { Controller, Post, UploadedFile, UseInterceptors, UseGuards } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { memoryStorage } from 'multer';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';

@Controller('upload')
export class UploadController {
  @Post()
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('admin')
  @UseInterceptors(FileInterceptor('file', {
    storage: memoryStorage(),
    fileFilter: (req, file, cb) => {
      const allowed = ['image/png','image/jpeg','image/gif','application/pdf'];
      cb(null, allowed.includes(file.mimetype));
    },
    limits: { fileSize: 5 * 1024 * 1024 }
  }))
  upload(@UploadedFile() file: Express.Multer.File) {
    // Safe: do not execute content; just store/validate
    return { ok: true, filename: file.filename };
  }
}

CVE References

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