Command Injection in Nestjs with Hmac Signatures
Command Injection in Nestjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an attacker can control part of a system command executed by the application. In NestJS, this risk can arise when you build an Hmac Signature verification flow that incorporates untrusted input into shell commands. For example, imagine an API endpoint that accepts a filePath parameter, computes an Hmac signature to validate a client-supplied signature, and then passes the file path to a native utility such as cat or tail via child_process. If the Hmac verification passes but the filePath is attacker-controlled and not properly sanitized, an attacker can inject shell metacharacters (e.g., ;, &, |, `, or $()) to execute arbitrary commands with the application’s privileges.
The combination of Hmac Signature integrity checks and dynamic command execution is dangerous because developers may assume that Hmac alone guarantees the safety of the data. Hmac ensures authenticity and integrity of the signed payload, but it does not constrain how that payload is used downstream. An attacker could supply a valid signature for a payload like file.txt; rm -rf / if the server concatenates user input into a shell command. This pattern often appears in integrations that call external binaries for file processing, log analysis, or format conversion. The vulnerability maps to the OWASP API Top 10 category Broken Object Level Authorization (BOLA) and Injection, and can lead to data exfiltration, service disruption, or full system compromise. Runtime scans performed by middleBrick can detect unsafe consumption patterns where untrusted data reaches external command execution, even when an Hmac check is present, because the scanner analyzes the unauthenticated attack surface and does not rely on authentication context.
Consider a NestJS controller that uses crypto.createHmac to verify a signature and then executes a shell command using execSync. If the verified payload includes user-controlled data used directly in the command string, the server is vulnerable. middleBrick’s LLM/AI Security checks and unsafe consumption tests are designed to surface these risks by correlating signature verification logic with command usage, highlighting where remediation is required to avoid injection despite valid Hmac verification.
Hmac Signatures-Specific Remediation in Nestjs — concrete code fixes
To mitigate Command Injection when using Hmac Signatures in NestJS, you must ensure that untrusted input never reaches a shell. The safest approach is to avoid shell execution entirely and use built-in Node.js APIs or well-maintained libraries for file and data operations. When shell interaction is unavoidable, rigorously validate and sanitize inputs, and use parameterized commands or allowlists.
Below are concrete code examples demonstrating secure practices.
Example 1: Hmac verification without shell execution
Verify the signature and process the file using Node.js filesystem APIs instead of shell commands:
import { Controller, Get, Query, BadRequestException } from '@nestjs/common';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
@Controller('files')
export class FilesController {
private readonly secret = process.env.HMAC_SECRET;
@Get()
getFile(@Query('file') file: string, @Query('signature') signature: string) {
if (!file || !signature) {
throw new BadRequestException('Missing file or signature');
}
const expected = crypto.createHmac('sha256', thissecret)
.update(file)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new BadRequestException('Invalid signature');
}
const safeBase = path.resolve('/var/data/uploads');
const filePath = path.resolve(safeBase, file);
if (!filePath.startsWith(safeBase)) {
throw new BadRequestException('Invalid file path');
}
if (!fs.existsSync(filePath)) {
throw new BadRequestException('File not found');
}
return fs.readFileSync(filePath);
}
}
This approach validates the Hmac, ensures the resolved path is within an allowed directory, and reads the file using fs.readFileSync, avoiding any shell invocation.
Example 2: If shell execution is required, sanitize rigorously and avoid direct concatenation
If you must call an external binary, validate the input against a strict allowlist and use arguments rather than shell string concatenation:
import { Controller, Get, Query, BadRequestException } from '@nestjs/common';
import * as crypto from 'crypto';
import { execFile } from 'child_process';
import { promisify } from 'util';
const execFileAsync = promisify(execFile);
@Controller('convert')
export class ConvertController {
private readonly secret = process.env.HMAC_SECRET;
@Get()
async convert(@Query('file') file: string, @Query('signature') signature: string) {
if (!file || !signature) {
throw new BadRequestException('Missing parameters');
}
const expected = crypto.createHmac('sha256', this.secret)
.update(file)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new BadRequestException('Invalid signature');
}
const allowedExtensions = ['.txt', '.csv'];
const ext = file.slice(file.lastIndexOf('.'));
if (!allowedExtensions.includes(ext)) {
throw new BadRequestException('File type not allowed');
}
// Use execFile with an array of arguments; do not pass a shell string
const { stdout } = await execFileAsync('cat', [file]);
return stdout;
}
}
Key remediation points: use execFile (not exec or shell forms), pass arguments as an array, validate file extension via an allowlist, and enforce Hmac verification before any processing. middleBrick’s CLI (middlebrick scan <url>) and GitHub Action can help identify places where user input reaches command execution so you can apply these fixes before deploying.
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 |
Frequently Asked Questions
Does Hmac verification alone prevent Command Injection in NestJS APIs?
How can I test my NestJS endpoints for Command Injection alongside Hmac Signature flows?
middlebrick scan <url>) to scan unauthenticated endpoints. It runs checks including unsafe consumption and input validation, and it correlates findings with OpenAPI specs to highlight where user-controlled data reaches command execution despite Hmac checks.