Command Injection in Nestjs with Bearer Tokens
Command Injection in Nestjs with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Command injection occurs when an attacker can inject and execute operating system commands via an application. In NestJS applications that accept user input and invoke shell commands, combining this capability with Bearer token handling can expose dangerous attack paths. The risk arises when endpoints protected by Bearer token authentication still allow uncontrolled input to reach system-level calls, such as those using child_process or exec-like functions.
Consider an endpoint that receives a filename in a request header or body and passes it to a shell command for processing. If the input is not strictly validated or sanitized, an attacker authenticated with a valid Bearer token can escape intended arguments and execute arbitrary commands. For example, a common pattern like using child_process.exec with concatenated strings can become vulnerable: exec('convert ' + userFile + ' output.png'). An attacker could supply a Bearer token to authenticate, then provide a filename such as '; rm -rf / #, leading to unintended shell command execution.
Even with Bearer token enforcement at the route level via guards, the application may still treat user-supplied data as safe if it originates from authenticated requests. This false sense of security can lead developers to skip input validation. NestJS guards verify tokens and roles but do not sanitize payloads. If an API endpoint uses token-based authorization without validating or escaping shell arguments, the combination of authentication and unchecked input creates a viable injection vector.
Real-world attack patterns include using environment variables or file paths that an attacker can influence. For instance, if a NestJS service reads a configuration value from user-controlled data and interpolates it into a shell command, the Bearer token becomes a credential that enables a authenticated command injection. The OWASP API Top 10 category '2023:3 Injection' highlights such risks, and mappings to compliance frameworks like PCI-DSS and SOC2 emphasize the need to treat authenticated inputs as untrusted when they reach system-level interfaces.
Tools like middleBrick scan for these patterns by correlating OpenAPI specifications with runtime behavior, identifying endpoints that accept authentication but pass unchecked data to shell commands. The scanner does not fix the code but provides prioritized findings with severity ratings and remediation guidance, helping developers understand where authentication and input handling must be decoupled.
Bearer Tokens-Specific Remediation in Nestjs — concrete code fixes
To remediate command injection in NestJS when using Bearer tokens, ensure that user input is never directly concatenated into shell commands. Use parameterized commands or dedicated libraries that avoid shell interpretation. Below are concrete code examples demonstrating secure practices.
- Secure command execution using
execFilewith an array of arguments:
import { Controller, Get, Header, ForbiddenException } from '@nestjs/common';
import { execFile } from 'child_process';
import { promisify } from 'util';
const execFileAsync = promisify(execFile);
@Controller('process')
export class ProcessController {
@Get()
async processFile(@Header('authorization') authHeader: string) {
// Assume token validation is done via a guard; focus on safe command usage
const filename = 'report.txt'; // derived from validated, non-user input
try {
const { stdout, stderr } = await execFileAsync('convert', [filename, 'output.png']);
return { stdout, stderr };
} catch (error) {
throw new ForbiddenException('File processing failed');
}
}
}
- Input validation and sanitization before any shell interaction:
import { Injectable, BadRequestException } from '@nestjs/common';
@Injectable()
export class ValidationService {
validateFilename(input: string): string {
const sanitized = input.replace(/[^a-zA-Z0-9._-]/g, '');
if (!sanitized || sanitized !== input) {
throw new BadRequestException('Invalid filename');
}
return sanitized;
}
}
- Using the validation service in a controller with Bearer token guard:
import { Controller, Post, Body, UseGuards } from '@nestjs/common';
import { ValidationService } from './validation.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('upload')
export class UploadController {
constructor(private readonly validationService: ValidationService) {}
@UseGuards(AuthGuard('jwt'))
@Post('file')
async uploadFile(@Body('name') name: string) {
const safeName = this.validationService.validateFilename(name);
// Proceed with safe filename, avoiding shell injection
return { message: 'File validated', filename: safeName };
}
}
These examples emphasize that Bearer tokens should only handle authentication, while input must be validated and executed via safe APIs. middleBrick can detect endpoints where authentication is present but input reaches shell commands, providing findings mapped to frameworks like OWASP API Top 10 to guide remediation.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |