Command Injection on Azure
How Command Injection Manifests in Azure
Command injection in Azure environments typically occurs when untrusted user input is incorporated into system commands without proper sanitization. Azure's serverless and PaaS offerings create unique attack surfaces where command injection can have devastating consequences.
The most common Azure-specific pattern involves Azure Functions using Node.js or Python runtimes where developers concatenate user input into shell commands. For example:
// Vulnerable Azure Function in Node.js
module.exports = async function (context, req) {
const fileName = req.query.file || '';
const command = `cat /data/${fileName}`;
const result = require('child_process').execSync(command);
context.res = { body: result };
return context.res;
};This function is vulnerable because the fileName parameter is directly interpolated into a shell command. An attacker could exploit this by requesting: /api/function?file=example.txt; rm -rf /, which would execute the additional rm -rf / command.
Azure Logic Apps present another attack vector. When using the "Run PowerShell script" or "Run Bash script" actions with dynamic content from previous steps, command injection becomes possible if the dynamic content isn't properly escaped. The Logic Apps Designer makes it easy to inadvertently create these vulnerabilities by allowing direct insertion of trigger outputs into script actions.
Azure Container Instances are particularly vulnerable when they execute commands based on user input. A common pattern involves using docker exec or similar commands where the container name or command comes from user input:
// Vulnerable Azure Container Instance management
const exec = require('child_process').exec;
const containerName = req.query.container;
const command = req.query.cmd || 'ls';
exec(`docker exec ${containerName} ${command}`, (err, stdout) => {
res.send(stdout);
});Azure App Service functions running on Windows can be exploited through command injection via the system() or exec() functions in various languages, potentially allowing attackers to execute PowerShell commands that bypass Azure's security controls.
Azure Kubernetes Service (AKS) deployments often include custom admission controllers or operators that execute commands based on YAML manifests submitted by users. If these controllers don't properly validate and sanitize input, command injection can occur at the cluster level.
Azure-Specific Detection
Detecting command injection in Azure requires both static code analysis and runtime monitoring. Azure Security Center and Defender for Cloud provide some detection capabilities, but they often miss complex injection patterns.
middleBrick's Azure-specific scanning includes several targeted checks:
- Function App command injection detection - identifies unsafe use of
exec(),spawn(),execSync()with user input - Logic App script injection - scans for unescaped dynamic content in script actions
- Container command injection - detects unsafe command construction in container management code
- ARM template injection - identifies dangerous parameter usage in deployment scripts
The scanner tests for command injection by sending payloads like ; ls -la, | cat /etc/passwd, and && whoami to API endpoints and monitoring for unexpected behavior or error messages that reveal system information.
For Azure Functions specifically, middleBrick analyzes the function.json configuration and runtime code to identify functions that accept user input and perform file operations or execute system commands. It then attempts to manipulate these commands to execute secondary payloads.
Azure Application Insights can be configured to detect command injection attempts by creating custom telemetry that flags suspicious command patterns. For example, monitoring for the presence of shell metacharacters (;, &, |, >, <) in unexpected contexts can help identify attacks in progress.
Network-level detection using Azure Network Watcher can identify command injection attempts that result in unusual outbound connections or data exfiltration patterns. This is particularly useful for detecting post-exploitation activities where attackers use command injection to establish persistence.
Azure-Specific Remediation
Remediating command injection in Azure requires a defense-in-depth approach. The primary mitigation is to eliminate the use of shell commands where possible, but when system commands are necessary, Azure provides several native approaches for safe execution.
For Azure Functions using Node.js, use the child_process module's array form instead of string commands:
// Secure version - array form prevents shell injection
const { execFile } = require('child_process');
module.exports = async function (context, req) {
const fileName = req.query.file || 'default.txt';
// Validate filename - only allow alphanumeric and specific extensions
if (!/^[a-zA-Z0-9_\.-]+$/.test(fileName)) {
return context.res = {
status: 400,
body: 'Invalid filename'
};
}
execFile('cat', ['/data/' + fileName], (err, stdout) => {
context.res = { body: stdout || 'Error reading file' };
});
};The array form of execFile ensures that arguments are passed directly to the executable without shell interpretation, eliminating command injection vectors.
For Azure Logic Apps, use the "Initialize variable" action to properly escape dynamic content before using it in script actions. Alternatively, use the built-in Azure functions like uriComponentToString() and replace() to sanitize inputs.
Azure Container Instances should use managed identities and Azure RBAC instead of command-based authentication. When commands are necessary, use the Azure CLI's built-in validation:
// Secure Azure CLI usage with validation
const { execSync } = require('child_process');
function safeExec(containerName, command) {
// Validate container name against Azure naming rules
if (!/^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$/.test(containerName)) {
throw new Error('Invalid container name');
}
// Use array form and avoid shell=True
const args = ['exec', containerName, command];
return execSync('az container exec ' + args.join(' '), { encoding: 'utf8' });
}Azure Key Vault integration provides another layer of security by storing sensitive commands and parameters that should never be exposed to user input. Functions can retrieve these from Key Vault at runtime rather than constructing them dynamically.
For AKS environments, implement Open Policy Agent (OPA) Gatekeeper policies that prevent the deployment of containers with dangerous command patterns. These policies can block deployments that include suspicious command arguments or use privileged containers inappropriately.
Azure Policy can enforce security standards across your Azure subscription, including rules that prevent the creation of resources with command injection vulnerabilities. Custom Azure Policy definitions can check for the use of dangerous APIs and flag or deny deployments that don't meet security requirements.
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 |