HIGH command injectionaspnethmac signatures

Command Injection in Aspnet with Hmac Signatures

Command Injection in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Command injection occurs when an attacker can cause an application to execute unintended operating system commands. In ASP.NET applications that use HMAC signatures to validate requests, a common misconfiguration is including user-controlled data inside the string that is signed without proper canonicalization, and then passing a field from the signed payload to a system process or shell. For example, if a signature is computed over a concatenation of user input fields and later the application uses one of those fields in Process.Start or System.Diagnostics.Process without validation, the signed value can be abused to inject shell metacharacters.

Consider an API that signs parameters such as action, resource, and target using HMAC-SHA256. If the server reuses the signed target value in a shell command to select a file or invoke a tool, and the signature does not bound the command template, an attacker who can influence target may append shell operators and commands. Because the signature validates only integrity (not semantics), the malicious additions may still produce a valid signature if the server does not enforce strict field separation and allowed values. This pattern is risky when the application runs with elevated privileges or exposes endpoints that trigger backend utilities.

In ASP.NET, a vulnerable implementation might compute the HMAC over raw query strings or form fields and then use one of those fields in Process invocations. For instance, reading a filename from a signed parameter and passing it directly to ffmpeg or tar allows an attacker to escape the expected argument boundaries using shell metacharacters like ;, &, or |. Even if the signature includes a timestamp or nonce, if the server does not validate the content and length of each signed field, the attack surface remains. This is compounded when the application deserializes JSON or form data into objects and then reconstructs a command line using string interpolation, because the HMAC may cover only a subset of the data used in the command.

An example attack chain: an endpoint accepts fileId and action, signs them, and later runs a system command such as convert {fileId}. If fileId is not strictly validated and the signature does not prevent extra parameters, an attacker can set fileId to ';cat /etc/passwd #. If the server reconstructs the command via string concatenation, the shell will execute the injected command. Because the signature appears valid, the request bypasses integrity checks. This illustrates why HMAC signatures must be paired with strict allowlists, canonical command templates, and avoidance of shell injection-prone APIs.

Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes

To remediate command injection when using HMAC signatures in ASP.NET, separate signing from command construction, validate all inputs against strict allowlists, and avoid passing raw user data to shell commands. Use a parameterized command pattern or a library that does not invoke a shell, and ensure the HMAC covers the exact data used for command decisions.

Example: Safe HMAC validation and command execution in ASP.NET Core

Use System.Security.Cryptography.HMACSHA256 to validate a signature, then map validated inputs to a predefined command template. Never concatenate raw input into a shell command.

using System;
using System.Security.Cryptography;
using System.Text;
using System.Diagnostics;

public class CommandService
{
    private static readonly byte[] Key = Convert.FromBase64String("YOUR_BASE64_KEY_HERE");

    public bool TryExecute(string fileId, string signature, out string output)
    {
        output = string.Empty;
        if (!IsValidSignature(fileId, signature))
        {
            return false;
        }

        // Strict allowlist: only safe file identifiers are permitted
        var allowedFiles = new System.Collections.Generic.HashSet<string> { "report", "export", "summary" };
        if (!allowedFiles.Contains(fileId))
        {
            return false;
        }

        // Use a process start that does not invoke a shell
        var startInfo = new ProcessStartInfo
        {
            FileName = "/usr/bin/convert", // absolute path
            Arguments = $"\"/data/in/{fileId}.pdf\" \" /data/out/{fileId}.png\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        using (var process = Process.Start(startInfo))
        {
            output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
        }
        return true;
    }

    private bool IsValidSignature(string fileId, string signature)
    {
        using (var hmac = new HMACSHA256(Key))
        {
            var computed = hmac.ComputeHash(Encoding.UTF8.GetBytes(fileId));
            var expected = Convert.ToBase64String(computed);
            // Use a time-constant comparison to avoid timing attacks
            return CryptographicOperations.FixedTimeEquals(
                Convert.FromBase64String(signature),
                Encoding.UTF8.GetBytes(expected));
        }
    }
}

Key practices:

  • Do not include command syntax (e.g., |, &, &&) in signed fields; keep the signature over canonical identifiers only.
  • Use allowlists for file names or action types; do not rely on blacklists.
  • Prefer ProcessStartInfo with UseShellExecute = false and absolute paths for executables.
  • Avoid passing raw user input directly to shell utilities; if shell features are required, use a controlled wrapper with strict validation.
  • Apply fixed-time comparisons for HMAC verification to prevent timing-based side channels.

Example: HMAC with JSON payload in ASP.NET Core controller

Sign a normalized JSON representation and validate before using any field in sensitive operations.

[ApiController]
[Route("api/[controller]")]
public class ExportController : ControllerBase
{
    private static readonly byte[] Key = Convert.FromBase64String("YOUR_BASE64_KEY_HERE");

    [HttpPost("export")]
    public IActionResult Export([FromBody] ExportRequest request)
    {
        // Recompute signature over a canonical JSON (sorted keys, no extra whitespace)
        var canonicalJson = System.Text.Json.JsonSerializer.Serialize(request, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
        string expectedSig;
        using (var hmac = new HMACSHA256(Key))
        {
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(canonicalJson));
            expectedSig = Convert.ToBase64String(hash);
        }

        if (!TimingSafeEquals(expectedSig, request.Signature))
        {
            return Unauthorized();
        }

        // Safe handling: map to a controlled command template
        if (!Enum.TryParse<ExportType>(request.Type, out var exportType))
        {
            return BadRequest("Invalid type");
        }

        // Use a non-shell executor or library appropriate to the operation
        // ...
        return Ok();
    }

    private bool TimingSafeEquals(string a, string b)
    {
        var aBytes = Encoding.UTF8.GetBytes(a);
        var bBytes = Encoding.UTF8.GetBytes(b);
        return CryptographicOperations.FixedTimeEquals(aBytes, bBytes);
    }
}

public class ExportRequest
{
    public string Type { get; set; }
    public string Signature { get; set; }
}

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Why does including user data in HMAC-signed fields still risk command injection?
If the server uses signed fields directly in shell commands without strict validation and canonical command templates, attackers can inject shell metacharacters. The signature ensures integrity of the included data, but does not restrict its semantics or prevent injection when the data is interpreted by a shell.
What is the safest way to use HMAC signatures in ASP.NET for operations that invoke external processes?
Use HMAC to sign only canonical identifiers, validate identifiers against an allowlist, and construct commands with parameterized templates or libraries that do not invoke a shell. Avoid concatenating raw user input into command strings and prefer ProcessStartInfo with UseShellExecute = false.