Back to skill

Security audit

Azure Bicep Deploy

Security checks for vulnerabilities and agentic risk

Overview

This Azure deployment skill is mostly purpose-aligned, but it includes unsafe copy-paste PowerShell helpers and live cloud deployment examples that can affect real Azure resources.

Review this skill before installing. Use it only in a non-production Azure subscription or with a least-privileged identity until the PowerShell helpers are fixed to pass arguments directly to az instead of using Invoke-Expression. Run what-if first, verify the active tenant and subscription, avoid hardcoding real registry passwords, and treat external Container Apps ingress as public internet exposure.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
references/deploy.md:77
Finding
PowerShell Command Injection in Azure Deployment Helper## Vulnerability Details **File Location**: `references/deploy.md`, lines 77–96 **Vulnerability Type**: PowerShell command injection through `Invoke-Expression` **Risk Level**: High ### Vulnerable Code ```powershell # Build the deployment command $deploymentName = "bicep-deploy-$(Get-Date -Format 'yyyyMMdd-HHmmss')" $command = "az deployment group create --resource-group $ResourceGroupName --name $deploymentName --template-file $TemplateFile" if (-not [string]::IsNullOrEmpty($ParametersFile)) { $command += " --parameters @$ParametersFile" } Write-Host "Environment: $Environment" -ForegroundColor Cyan Write-Host "Resource Group: $ResourceGroupName" -ForegroundColor Cyan Write-Host "Template: $TemplateFile" -ForegroundColor Cyan Write-Host "" if ($WhatIf) { Write-Host "Running What-If analysis..." -ForegroundColor Yellow $command = $command -replace "deployment group create", "deployment group what-if" } Write-Host "Executing: $command" -ForegroundColor Gray Write-Host "" # Execute Invoke-Expression $command ``` ### Technical Analysis The script interpolates the user-controlled `$ResourceGroupName`, `$TemplateFile`, and `$ParametersFile` values into a PowerShell command string. It then executes the resulting string with `Invoke-Expression`. `Invoke-Expression` parses its argument as PowerShell source code rather than passing each value to Azure CLI as an isolated argument. Consequently, PowerShell metacharacters contained in any interpolated parameter can terminate or alter the intended Azure CLI command and introduce an additional command. Azure-side resource-name validation does not prevent this issue because PowerShell processes the injected syntax locally before Azure CLI receives its arguments. The vulnerability is reachable in both ordinary deployment and `-WhatIf` modes. ### Attack Path 1. An attacker influences one of the script arguments, such as `ResourceGroupName`, `Tem ...[truncated 1163 chars]
Remediation
## Remediation Suggestions Remove `Invoke-Expression` and invoke Azure CLI using a PowerShell argument array: ```powershell $azArguments = @( "deployment", "group", "create", "--resource-group", $ResourceGroupName, "--name", $deploymentName, "--template-file", $TemplateFile ) if (-not [string]::IsNullOrEmpty($ParametersFile)) { $azArguments += @("--parameters", "@$ParametersFile") } & az @azArguments if ($LASTEXITCODE -ne 0) { throw "Azure deployment failed with exit code $LASTEXITCODE." } ``` For `-WhatIf`, construct a separate argument array rather than performing string replacement. Additionally: - Restrict `$Environment` with `ValidateSet("dev", "staging", "prod")`. - Resolve template and parameter paths with `Resolve-Path`. - Require supported file extensions. - Verify that parameter files exist and are regular files. - Avoid logging values that may contain sensitive deployment parameters. - Run deployments using a least-privileged Azure identity.

T09 · Insecure Skill Coding Practices

Error
Location
references/bicep-build.md:51
Finding
PowerShell Command Injection in Bicep Build Helper## Vulnerability Details **File Location**: `references/bicep-build.md`, lines 51–54 **Vulnerability Type**: PowerShell command injection through `Invoke-Expression` **Risk Level**: High ### Vulnerable Code ```powershell $command = "az bicep build --file $BicepFile --outfile $OutputFile" Write-Host "Running: $command" -ForegroundColor Gray Invoke-Expression $command ``` ### Technical Analysis `$BicepFile` and `$OutputFile` are caller-controlled strings. They are embedded without quoting or escaping into a command string that is subsequently interpreted by `Invoke-Expression`. A filename containing PowerShell metacharacters can change the syntactic structure of the command. This is not merely an argument-parsing error: `Invoke-Expression` treats the generated text as executable PowerShell source code, permitting an additional command to run. The script does not resolve the paths, validate their extensions, constrain the output location, or isolate them as native-process arguments. ### Attack Path 1. An attacker supplies or causes a user to supply a crafted `BicepFile` or `OutputFile` argument. 2. The value includes PowerShell syntax that alters the generated command. 3. The script interpolates the value directly into `$command`. 4. `Invoke-Expression` evaluates the injected syntax. 5. The attacker's command executes with the current user's local privileges. This can also be exploited through an automated workflow if untrusted repository data, filenames, or pipeline variables are passed to this helper. ### Impact Assessment Exploitation provides arbitrary command execution under the account running the build. The attacker may access source code, pipeline secrets, local credentials, generated ARM templates, and other files available to that account. In a CI/CD environment, the scope may include build agents, deployment credentials, artifact stores, and cloud resources accessible through environment variable ...[truncated 27 chars]
Remediation
## Remediation Suggestions Pass arguments directly to Azure CLI without constructing executable PowerShell text: ```powershell $resolvedInput = (Resolve-Path -LiteralPath $BicepFile).Path if ([System.IO.Path]::GetExtension($resolvedInput) -ne ".bicep") { throw "The input must be a Bicep file." } $outputFullPath = [System.IO.Path]::GetFullPath($OutputFile) & az bicep build --file $resolvedInput --outfile $outputFullPath if ($LASTEXITCODE -ne 0) { throw "Bicep build failed with exit code $LASTEXITCODE." } ``` Also constrain output paths when this helper runs in a service or CI environment, reject paths outside the intended workspace, and ensure symbolic links cannot redirect output to sensitive files.

T09 · Insecure Skill Coding Practices

Error
Location
references/validate.md:46
Finding
PowerShell Command Injection in Bicep Validation and What-If Operations## Vulnerability Details **File Location**: `references/validate.md`, lines 46–86 **Vulnerability Type**: PowerShell command injection through `Invoke-Expression` **Risk Level**: High ### Vulnerable Code The Bicep syntax-validation path constructs and evaluates a command string: ```powershell $command = "az bicep build --file $TemplateFile" Write-Host "Running: $command" -ForegroundColor Gray Invoke-Expression $command ``` The Azure What-If path repeats the same unsafe pattern with both the resource-group name and template path: ```powershell $command = "az deployment group what-if --resource-group $ResourceGroupName --template-file $TemplateFile" if (Test-Path "params/dev.json") { $command += " --parameters @params/dev.json" } Write-Host "Running: $command" -ForegroundColor Gray Invoke-Expression $command ``` ### Technical Analysis The script uses untrusted `$TemplateFile` and `$ResourceGroupName` values to generate PowerShell command text. Because the resulting text is passed to `Invoke-Expression`, command separators and other expression syntax are interpreted locally. The extension check performed earlier for `$TemplateFile` does not constitute safe argument handling. A crafted string may still contain executable syntax while producing an extension that reaches the relevant branch. The What-If path is additionally reachable through the unconstrained resource-group parameter. Although Azure What-If is intended as a preview operation, the injected local command is not restricted to preview behavior. It can execute any operation available to the current process. ### Attack Path 1. An attacker controls a template path, resource-group argument, pipeline variable, or wrapper-script input. 2. The attacker introduces PowerShell syntax into that value. 3. The validation helper embeds the value in `$command`. 4. `Invoke-Expression` evaluates the assembled command as PowerShell code. 5. The in ...[truncated 799 chars]
Remediation
## Remediation Suggestions Eliminate both uses of `Invoke-Expression`. Invoke Azure CLI using direct arguments: ```powershell $resolvedTemplate = (Resolve-Path -LiteralPath $TemplateFile).Path if ($extension -eq ".bicep") { & az bicep build --file $resolvedTemplate if ($LASTEXITCODE -ne 0) { throw "Bicep syntax validation failed." } } if ($WhatIf -and -not [string]::IsNullOrEmpty($ResourceGroupName)) { $azArguments = @( "deployment", "group", "what-if", "--resource-group", $ResourceGroupName, "--template-file", $resolvedTemplate ) if (Test-Path -LiteralPath "params/dev.json") { $azArguments += @("--parameters", "@params/dev.json") } & az @azArguments if ($LASTEXITCODE -ne 0) { throw "What-If analysis failed." } } ``` Further hardening should include: - Validate that the template path exists and is a regular file. - Allow only `.bicep` and `.json` extensions using case-insensitive comparison. - Keep template and parameter paths within an approved workspace. - Validate resource-group names against Azure's documented naming constraints. - Use a dedicated least-privileged identity for What-If operations. - Avoid automatically selecting `params/dev.json`; require the intended parameter file explicitly to prevent accidental environment mismatch.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Missing User Warnings

Medium
Confidence
91% confidence
Finding
These instructions directly invoke `az deployment group create`, which can create, modify, or replace Azure resources and potentially incur cost. The skill provides executable deployment commands without an explicit warning to confirm target subscription, resource group, scope, and billing impact, increasing the risk of accidental production changes or unintended spend.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The quick deploy one-liner is especially risky because it is presented as a copy-paste command that performs an immediate live deployment with no built-in pause, review step, or warning. This lowers user friction and makes accidental execution against the wrong environment or subscription more likely, leading to unintended infrastructure changes and cloud charges.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The script constructs a shell command by interpolating user-controlled values ($BicepFile and $OutputFile) into a string and then executes it with Invoke-Expression. This enables PowerShell command injection if an attacker supplies crafted input containing metacharacters or additional commands, which is especially dangerous because the documentation presents the script as a simple build helper and does not signal that arbitrary command execution may occur.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The example enables `external: true` ingress, which creates a publicly reachable service, but the reference text provides no warning that this exposes the app to the internet. In a copy-paste reference document, users may deploy internet-accessible workloads unintentionally, increasing the risk of attack surface exposure, probing, and accidental publication of internal services.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The example includes inline secret configuration with a placeholder registry password but does not warn users against hardcoding credentials or describe safer secret-handling patterns. In reference material, this can normalize insecure handling of secrets and lead users to embed real credentials in templates, source control, or logs.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation shows direct deployment commands, including production, without a prominent warning that this performs live Azure resource changes by default. In an agent skill or copied runbook context, this increases the risk of accidental execution against real environments, unintended infrastructure changes, and production impact because users may treat the example as safe or dry-run behavior.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The script is presented as a deployment helper, but it also installs Bicep automatically on the host via `az bicep install`. That side effect modifies the local system and may violate change-control expectations or enable unreviewed software installation in automation environments, especially when users believe they are only performing an Azure deployment.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This markdown file documents a script that creates or updates an output JSON file, but it does not warn users that running the command will write to the specified path or to a default path derived from the input file. Because SQP-2 applies to markdown files when behaviors affecting user data or system state are not disclosed, this omission is a valid missing-warning finding.

Static analysis

No suspicious patterns detected.