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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.