Skip to content
Report library
Purpose / Other

Azure Cost Skill Security Audit

What the author says it does (original text)

Azure cost management: query costs, forecast spending, optimize to reduce waste. WHEN: \"Azure costs\", \"Azure bill\", \"cost breakdown\", \"how much am I spending\", \"forecast spending\", \"optimize costs\", \"reduce spending\", \"orphaned resources\", \"rightsize VMs\", \"cost spike\", \"reduce storage costs\", \"AKS cost\". DO NOT USE FOR: deploying resources, provisioning, diagnostics, or se

Independent security check

Security risks found

Files checked
23
Risks found
6
Could it run dangerous commands?Looks for programs run straight after downloading, remote control of your computer, and hidden commands.No risks found
Could it expose your files or keys?Looks for uploads of files containing passwords or keys, and keys written directly in the code.Risks found: 2
Medium risk

Scope priority can select a broader management group when narrower identifiers are available

Source references: 2
What we found

The scope-resolution table ranks Management Group—the broadest organizational scope—ahead of Resource Group and Subscription, potentially expanding cost and resource queries.

Why this matters

The agent could read and summarize billing and resource metadata from unrelated subscriptions or groups, placing additional sensitive business data in responses and local reports.

This is an active scope-selection rule: when several identifiers are present, it ranks the management group—explicitly described as the broadest organizational scope—ahead of resource group and subscription. A query could therefore cover more subscriptions and organizational data than the user expected. The user can require the resolved scope to be shown and confirmed before management-group queries.

cost-query/dimensions-by-scope.md:155In the instructionsOpen original file
## Scope Resolution PriorityWhen multiple scope identifiers are available in context, use the following priority order (highest first):| Priority | Scope | Notes ||----------|-------|-------|| 1 | Management Group | Broadest organizational scope. || 2 | Resource Group | Narrowest resource scope. || 3 | Subscription | Default scope for most queries. || 4 | Billing Profile + Invoice Section | MCA billing hierarchy. |
Show 1 other places
cost-query/workflow.md:5In the instructionsOpen original file
## Step 1: Determine ScopeIdentify the Azure scope for the cost query from the Scope Reference table in the main [SKILL.md](../SKILL.md#scope-reference-shared-across-all-workflows).
Low risk

Billing results and resource portal links are retained as workspace audit artifacts

Source references: 5
What we found

The Skill requires saving all queries and responses and adding Azure Portal links containing tenant, subscription, resource-group, and resource names. No retention period or file-access restriction is specified.

Why this matters

Shared workspaces, backups, artifact uploads, or later commits could expose billing and infrastructure metadata. The supplied source does not show active exfiltration.

The Skill requires saving all queries and responses, timestamped cost results, and portal links containing tenant, subscription, resource-group, and resource names. This leaves sensitive billing and resource inventory in `output/`; only temporary files are cleaned, and no retention period or access control is specified. The user can restrict output location and permissions, require redaction, and set an expiration or deletion schedule.

references/tools-and-best-practices.md:29In the instructionsOpen original file
- Always include the `ClientType: GitHubCopilotForAzure` header on all Cost Management API requests (`--headers "ClientType=GitHubCopilotForAzure"` in `az rest`)- Save audit trail with all queries and responses- Include Azure Portal links for all resources- For costs < $10/month, emphasize operational improvements over financial savings
Show 4 other places
cost-optimization/report-template.md:53In the instructionsOpen original file
Include Azure Portal links for all resources using this format:```texthttps://portal.azure.com/#@<TENANT_ID>/resource/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/<RESOURCE_PROVIDER>/<RESOURCE_TYPE>/<RESOURCE_NAME>/overview```
cost-optimization/report-template.md:59In the instructionsOpen original file
## Audit TrailSave cost query results to `output/cost-query-result<YYYYMMDD_HHMMSS>.json` for reproducibility.
cost-optimization/workflow.md:194In the instructionsOpen original file
## Step 7: Generate Optimization ReportGenerate a report to `output/costoptimizereport<YYYYMMDD_HHMMSS>.md` that includes an executive summary, cost breakdown by service, free tier analysis, orphaned resources, prioritized optimization recommendations, and implementation commands. Save cost query results to `output/cost-query-result<YYYYMMDD_HHMMSS>.json` for audit trail, then clean up temporary files.
cost-optimization/report-template.md:63In the instructionsOpen original file
## CleanupAfter generating the report, remove temporary files:```powershellRemove-Item -Path "temp" -Recurse -Force -ErrorAction SilentlyContinue```
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.Risks found: 3
Medium risk

Cleanup recursively force-deletes the entire relative temp directory

Source references: 2
What we found

The workflows create specific files such as `temp/cost-query.json`, but the final template removes the whole `temp` directory rather than only files created by the Skill.

Why this matters

If a pre-existing temp directory in the working folder contains unrelated files, they can be recursively and forcibly deleted. Suppressed errors may make the loss less visible.

The workflow creates a query file under the relative `temp` path, but cleanup recursively and forcibly removes the entire directory rather than only files created by this Skill. If the working directory already contains an unrelated `temp` directory, its contents would also be deleted. The user can require a uniquely named temporary directory and cleanup limited to created paths.

cost-query/workflow.md:47In the instructionsOpen original file
**Create cost query file:**Create `temp/cost-query.json` with:```json
Show 1 other places
cost-optimization/report-template.md:63In the instructionsOpen original file
## CleanupAfter generating the report, remove temporary files:```powershellRemove-Item -Path "temp" -Recurse -Force -ErrorAction SilentlyContinue```
Medium risk

The baseline storage lifecycle policy automatically deletes snapshots and versions after 90 days

Source references: 4
What we found

The Skill recommends a baseline policy containing automatic deletion actions for snapshots and blob versions, without template exclusions for legal holds, backups, immutable data, or critical prefixes.

Why this matters

Once deployed, snapshots and versions older than 90 days are continuously deleted, which can impair recovery, audit evidence, or compliance retention.

The document recommends this as a baseline for accounts without lifecycle management, and it automatically deletes snapshots and blob versions older than 90 days. The template does not restrict critical prefixes or state backup/legal-hold exclusions, so applying it could remove data or recovery points. General safety rules call for approval and rollback, but do not remove the template’s risk. The user can require an impact inventory, retention review, and recovery plan first.

cost-optimization/services/storage/azure-storage.md:48In the instructionsOpen original file
## Lifecycle Policy TemplateRecommend this baseline policy for accounts without lifecycle management:
Show 3 other places
cost-optimization/services/storage/azure-storage.md:79In the instructionsOpen original file
    },    {      "name": "delete-old-snapshots",      "type": "Lifecycle",      "definition": {        "actions": {          "snapshot": {            "delete": { "daysAfterCreationGreaterThan": 90 }          }        },        "filters": { "blobTypes": ["blockBlob"] }      }
cost-optimization/services/storage/azure-storage.md:91In the instructionsOpen original file
    },    {      "name": "delete-old-versions",      "type": "Lifecycle",      "definition": {        "actions": {          "version": {            "delete": { "daysAfterCreationGreaterThan": 90 }          }        },        "filters": { "blobTypes": ["blockBlob"] }      }
references/tools-and-best-practices.md:45In the instructionsOpen original file
- Get approval before deleting resources- Test changes in non-production first- Provide dry-run commands for validation- Include rollback procedures
Medium risk

Shallow status checks can label still-needed resources for immediate deletion

Source references: 6
What we found

Redis rules recommend deletion based only on Failed state or Creating for over four hours, while storage rules use an empty disk `managedBy` value. The report template then describes orphaned resources as immediately deletable. These signals do not establish absence of an owner, data, or recovery purpose.

Why this matters

If a user trusts and approves the generated commands, caches or disks retained for incident analysis, disaster recovery, migration, or data preservation could be deleted.

The rules treat failed Redis caches, caches creating for over four hours, and disks with an empty `managedBy` field as deletion candidates; the report template further calls orphaned resources immediately deletable. Those signals alone do not prove there is no data, dependency, or recovery use. Explicit approval is required elsewhere, but the recommendation can still mislead decisions. The user can require ownership, dependency, activity, backup, and recovery checks first.

cost-optimization/services/redis/azure-cache-for-redis.md:21In the instructionsOpen original file
| Priority | Rule | Detection Logic | Recommendation | Avg Savings ||----------|------|----------------|----------------|-------------|| 🔴 Critical | Failed Cache | `provisioningState == 'Failed'` | Delete immediately | $50-300/mo || 🔴 Critical | Stuck Creating | `provisioningState == 'Creating'` AND age >4 hours | Delete/support ticket | $50-300/mo || 🟠 High | Premium in Dev | `sku.name == 'Premium'` AND `tags.environment in ['dev','test','staging']` | Downgrade to Standard | $175/mo |
Show 5 other places
cost-optimization/services/storage/azure-storage.md:21In the instructionsOpen original file
| Priority | Rule | Detection Logic | Recommendation | Avg Savings ||----------|------|----------------|----------------|-------------|| 🔴 Critical | Orphaned Managed Disks (Compute) | Managed disks with `managedBy` empty (billed as storage) | Delete or snapshot and delete | $20-500/mo || 🔴 Critical | Premium in Dev | `sku.name` contains `Premium` AND `tags.environment in ['dev','test','staging']` | Downgrade to Standard | $50-400/mo |
cost-optimization/report-template.md:23In the instructionsOpen original file
## Orphaned Resources (Immediate Savings)[From azqr — resources that can be deleted immediately]
references/tools-and-best-practices.md:32In the instructionsOpen original file
- For costs < $10/month, emphasize operational improvements over financial savings- Never execute destructive operations without explicit approval- On 429 responses, check all `x-ms-ratelimit-microsoft.costmanagement-*-retry-after` headers (`qpu-retry-after`, `entity-retry-after`, `tenant-retry-after`), wait for the longest value, and don't retry until that duration has elapsed. The per-scope limit (4 requests/minute) is the most restrictive.
cost-optimization/services/redis/azure-cache-for-redis.md:23In the instructionsOpen original file
|----------|------|----------------|----------------|-------------|| 🔴 Critical | Failed Cache | `provisioningState == 'Failed'` | Delete immediately | $50-300/mo || 🔴 Critical | Stuck Creating | `provisioningState == 'Creating'` AND age >4 hours | Delete/support ticket | $50-300/mo || 🟠 High | Premium in Dev | `sku.name == 'Premium'` AND `tags.environment in ['dev','test','staging']` | Downgrade to Standard | $175/mo |
cost-optimization/services/storage/azure-storage.md:23In the instructionsOpen original file
|----------|------|----------------|----------------|-------------|| 🔴 Critical | Orphaned Managed Disks (Compute) | Managed disks with `managedBy` empty (billed as storage) | Delete or snapshot and delete | $20-500/mo || 🔴 Critical | Premium in Dev | `sku.name` contains `Premium` AND `tags.environment in ['dev','test','staging']` | Downgrade to Standard | $50-400/mo |
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.No risks found
Could it mislead the AI or hide text?Checks the skill instructions for requests to ignore you, influence the report, or hide text in invisible characters.No risks found
Could it change links or payment recipients without asking?Looks for forced referral or payment changes combined with instructions to hide the change.Risks found: 1
Low risk

All Cost API requests are labeled as the GitHubCopilotForAzure client

Source references: 3
What we found

The Skill mandates `ClientType=GitHubCopilotForAzure` even though the supplied source does not establish that the actual client is GitHub Copilot for Azure.

Why this matters

Azure-side client attribution, usage telemetry, and per-client throttling may be recorded under that product name, making audit records less representative of the true caller.

The Skill explicitly requires every Cost Management request to carry `ClientType=GitHubCopilotForAzure`, and its executable examples transmit that value. If the runtime is not that client, this sends Azure a potentially inaccurate client identity that could affect telemetry, quota attribution, or audit interpretation; the source does not establish how Azure uses it. The user can ask for the official requirement and an option to omit or accurately set it outside Copilot.

references/tools-and-best-practices.md:28In the instructionsOpen original file
- Use REST API for cost queries (more reliable than `az costmanagement query`)- Always include the `ClientType: GitHubCopilotForAzure` header on all Cost Management API requests (`--headers "ClientType=GitHubCopilotForAzure"` in `az rest`)- Save audit trail with all queries and responses
Show 2 other places
cost-query/guardrails.md:146In the instructionsOpen original file
|-------|-------|| Per User | 20 requests per minute || Per Scope | 4 requests per minute || Per Tenant | 12 requests per 10 seconds, 60 requests per minute, 600 requests per hour || Per Client Type | 2,000 requests per minute |
cost-query/workflow.md:77In the instructionsOpen original file
# Query using REST API (more reliable than az costmanagement query)az rest --method post `  --url "<scope>/providers/Microsoft.CostManagement/query?api-version=2023-11-01" `  --headers "ClientType=GitHubCopilotForAzure" `  --body '@temp/cost-query.json'```

Inside this skill

5 instruction sections

The Skill routes requests into historical cost queries, cost optimization, or future forecasts. Query and forecast workflows send POST requests to Azure Cost Management through an authenticated Azure CLI session.

View source
SKILL.md:16In the instructionsOpen original file
| User Intent | Workflow ||-------------|----------|| Understand current costs | [Cost Query](cost-query/workflow.md) || Reduce costs / find waste | [Cost Optimization](cost-optimization/workflow.md) || Project future costs | [Cost Forecast](cost-forecast/workflow.md) |
cost-query/workflow.md:43In the instructionsOpen original file
## Step 5: Construct and Execute the API CallUse `az rest` to call the Cost Management Query API.

The optimization workflow requires an authenticated Azure CLI session and Cost Management Reader, Monitoring Reader, and Reader roles on the target scope. These roles expose billing, monitoring, and resource-inventory data but do not require a write role.

View source
cost-optimization/workflow.md:7In the instructionsOpen original file
## Step 0: Validate Prerequisites**Required Tools:**- Azure CLI installed and authenticated (`az login`)- Azure CLI extensions: `costmanagement`, `resource-graph`- Azure Quick Review (azqr) installed — See [Azure Quick Review](./azure-quick-review.md)**Required Permissions:**- Cost Management Reader role- Monitoring Reader role- Reader role on subscription/resource group

Optimization scans for orphaned resources, queries recent costs and utilization metrics, and saves a local report plus raw query results under output, including resource recommendations and implementation commands.

View source
cost-optimization/workflow.md:99In the instructionsOpen original file
## Step 2: Run Azure Quick ReviewRun azqr to find orphaned resources (immediate cost savings):**Reference**: [Azure Quick Review](./azure-quick-review.md)```yamlazure__extension_azqr  subscription: "<SUBSCRIPTION_ID>"  resource-group: "<RESOURCE_GROUP>"  # optional```**What to look for:**- Orphaned resources: unattached disks, unused NICs, idle NAT gateways- Over-provisioned resources: excessive retention periods, oversized SKUs- Missing cost tags
cost-optimization/workflow.md:194In the instructionsOpen original file
## Step 7: Generate Optimization ReportGenerate a report to `output/costoptimizereport<YYYYMMDD_HHMMSS>.md` that includes an executive summary, cost breakdown by service, free tier analysis, orphaned resources, prioritized optimization recommendations, and implementation commands. Save cost query results to `output/cost-query-result<YYYYMMDD_HHMMSS>.json` for audit trail, then clean up temporary files.

The Skill explicitly requires approval before destructive operations, non-production testing, dry-run commands, and rollback procedures. These are important safeguards when its deletion or downgrade recommendations are acted upon.

View source
references/tools-and-best-practices.md:43In the instructionsOpen original file
## Safety Requirements- Get approval before deleting resources- Test changes in non-production first- Provide dry-run commands for validation- Include rollback procedures
Start here · InstructionsSKILL.md
azure-cost
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source.

File reference map

References: 37
Files making referencesReferenced content
Lines show actual file references, not execution order. Select a node to highlight its connections and inspect the files and source locations. Dashed lines include files that still need locating.
Files and check records23 files

Coverage and gaps

Content covered in each file

These are the source ranges included in this check, not a guarantee that every issue has been resolved.

  • SKILL.mdFull text included
  • cost-forecast/workflow.mdFull text included
  • cost-optimization/sdk/azure-resource-manager-redis-dotnet.mdFull text included
  • cost-optimization/services/redis/azure-cache-for-redis.mdFull text included
  • cost-optimization/services/storage/azure-storage.mdFull text included
  • cost-optimization/workflow.mdFull text included
  • cost-query/workflow.mdFull text included
  • references/tools-and-best-practices.mdFull text included
  • cost-forecast/error-handling.mdFull text included
  • cost-forecast/examples.mdFull text included
  • cost-forecast/guardrails.mdFull text included
  • cost-forecast/request-body-schema.mdFull text included
  • cost-optimization/auth-best-practices.mdFull text included
  • cost-optimization/azure-aks-anomalies.mdFull text included
  • cost-optimization/azure-aks-cost-addon.mdFull text included
  • cost-optimization/azure-quick-review.mdFull text included
  • cost-optimization/azure-resource-graph.mdFull text included
  • cost-optimization/report-template.mdFull text included
  • cost-query/dimensions-by-scope.mdFull text included
  • cost-query/error-handling.mdFull text included
  • cost-query/examples.mdFull text included
  • cost-query/guardrails.mdFull text included
  • cost-query/request-body-schema.mdFull text included

This report is for the version above. We read the available code and instructions without running the skill or checking extra packages it installs. This is not a promise of safety: a different version or setup may behave differently.

  • SKILL.mdInstructions
  • cost-forecast/error-handling.mdSupporting file
  • cost-forecast/examples.mdSupporting file
  • cost-forecast/guardrails.mdSupporting file
  • cost-forecast/request-body-schema.mdSupporting file
  • cost-forecast/workflow.mdSupporting file
  • cost-optimization/auth-best-practices.mdSupporting file
  • cost-optimization/azure-aks-anomalies.mdSupporting file
  • cost-optimization/azure-aks-cost-addon.mdSupporting file
  • cost-optimization/azure-quick-review.mdSupporting file
  • cost-optimization/azure-resource-graph.mdSupporting file
  • cost-optimization/report-template.mdSupporting file
  • cost-optimization/sdk/azure-resource-manager-redis-dotnet.mdSupporting file
  • cost-optimization/services/redis/azure-cache-for-redis.mdSupporting file
  • cost-optimization/services/storage/azure-storage.mdSupporting file
  • cost-optimization/workflow.mdSupporting file
  • cost-query/dimensions-by-scope.mdSupporting file
  • cost-query/error-handling.mdSupporting file
  • cost-query/examples.mdSupporting file
  • cost-query/guardrails.mdSupporting file
  • cost-query/request-body-schema.mdSupporting file
  • cost-query/workflow.mdSupporting file
  • references/tools-and-best-practices.mdSupporting file

Operations mentioned in code and instructions

Connect to websites
cost-forecast/error-handling.md:13In the instructionsOpen original file
| 429 | Too Many Requests | Rate limited — QPU, entity, or tenant quota exceeded | Check all `x-ms-ratelimit-microsoft.costmanagement-*-retry-after` headers (`qpu`, `entity`, `tenant`). Wait for the **longest** value before retrying. || 503 | Service Unavailable | Temporary service issue | Check [Azure Status](https://status.azure.com) for service health. |
cost-forecast/error-handling.md:46In the instructionsOpen original file
| 424 | ❌ No | Training data issue — retrying will not help. Fall back to actual costs or use **the Cost Query workflow (Part 1)** || 503 | ❌ No | Do not retry. Check [Azure Status](https://status.azure.com) for service health. |
cost-forecast/workflow.md:119In the instructionsOpen original file
| 429 | Rate limited | Check all `x-ms-ratelimit-microsoft.costmanagement-*-retry-after` headers (`qpu`, `entity`, `tenant`). Wait for the **longest** value. **Max 3 retries.** || 503 | Service unavailable | Check [Azure Status](https://status.azure.com). |
Run commands
cost-forecast/workflow.md:77In the instructionsOpen original file
**Execute:**```powershellNew-Item -ItemType Directory -Path "temp" -Force
cost-optimization/auth-best-practices.md:16In the instructionsOpen original file
| **CI/CD pipelines** | `AzurePipelinesCredential` / `WorkloadIdentityCredential` | Scoped to pipeline identity || **Local development** | `DefaultAzureCredential` | Chains CLI, PowerShell, and VS Code credentials for convenience |
cost-optimization/auth-best-practices.md:81In the instructionsOpen original file
2. **Azure Developer CLI** — `azd auth login`3. **Azure PowerShell** — `Connect-AzAccount`4. **Visual Studio / VS Code** — sign in via Azure extension
Read keys or account settings
cost-optimization/auth-best-practices.md:16In the instructionsOpen original file
| **CI/CD pipelines** | `AzurePipelinesCredential` / `WorkloadIdentityCredential` | Scoped to pipeline identity || **Local development** | `DefaultAzureCredential` | Chains CLI, PowerShell, and VS Code credentials for convenience |
cost-optimization/auth-best-practices.md:32In the instructionsOpen original file
var credential = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"    ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials
cost-optimization/auth-best-practices.md:33In the instructionsOpen original file
var credential = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"    ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials    : new ManagedIdentityCredential();                      // production — deterministic, no fallback chain
Lines read
2,431
File checksum (to compare versions)
a04f205093900294eabd053b13237ce52f698d3d6f38c85049bc31aea7e3b9cc