Back to skill

Security audit

power-automate-build

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent Power Automate deployment guide, but one testing recipe can leave a temporary schema-free HTTP trigger on a live flow if testing fails.

Install only if you are comfortable letting an agent create and update live Power Automate flows through FlowStudio MCP. Use least-privilege connections, require explicit approval before any test run or trigger change, avoid the temporary HTTP-trigger recipe unless rollback is guaranteed, use explicit schemas where possible, and verify the final deployed trigger and flow state after testing.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:420
Finding

Temporary Schema-Free HTTP Trigger May Persist After Test Failure

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 420-455
Vulnerability Type: Incomplete rollback of a temporary externally accessible trigger
Risk Level: High

Vulnerable Code

python
production_trigger = definition["triggers"]
definition["triggers"] = {
    "manual": {"type": "Request", "kind": "Http", "inputs": {"schema": {}}}
}

result = mcp("update_live_flow",
    environmentName=ENV,
    flowName=FLOW_ID,       # omit if creating new
    definition=definition,
    connectionReferences=connection_references,
    displayName="Overdue Invoice Notifications")
FLOW_ID = FLOW_ID or result["created"]

test = mcp("trigger_live_flow", environmentName=ENV, flowName=FLOW_ID,
           body={"sample": "payload"})
runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=1)

if runs[0]["status"] == "Failed":
    err = mcp("get_live_flow_run_error",
        environmentName=ENV, flowName=FLOW_ID, runName=runs[0]["name"])
    raise Exception(err["failedActions"][-1])

definition["triggers"] = production_trigger
mcp("update_live_flow",
    environmentName=ENV,
    flowName=FLOW_ID,
    definition=definition,
    connectionReferences=connection_references)

Technical Analysis

The testing procedure replaces the production trigger with an HTTP request trigger whose schema is empty, allowing arbitrary valid JSON. Restoration of the production trigger occurs only after the test and run-status inspection complete successfully.

If the test run fails, the explicit raise Exception(...) executes before restoration. An MCP error, timeout, interruption, cancellation, malformed response, or an empty runs result can similarly prevent the cleanup code from running. The deployed flow may consequently retain the temporary HTTP trigger indefinitely.

The temporary trigger is not inherently malicious and supports the Skill's declared testing functionality. However, deploying it directly over the target flow without guaranteed rollb ...[truncated 1586 chars]

Remediation
View remediation

Remediation Suggestions

  1. Wrap temporary-trigger deployment and testing in try/finally, restoring the production trigger in the finally block regardless of test outcome.
  2. After restoration, call get_live_flow and verify that the deployed trigger exactly matches the saved production trigger.
  3. If rollback fails, immediately stop the flow with set_live_flow_state and report the failure prominently to the user.
  4. Prefer creating an isolated disposable test flow rather than replacing the trigger on the production flow.
  5. Use an explicit, restrictive test schema instead of "schema": {} and validate all test payload fields.
  6. Add deployment-result and response-shape checks before accessing result["created"], runs[0], or nested error fields.
  7. Record the original flow state and restore it after testing.
  8. Require explicit user confirmation not only before running the test, but also before temporarily changing the deployed trigger.
  9. Ensure signed callback URLs are never logged, committed, or returned to untrusted callers.
  10. Add automated cleanup for stale temporary test flows or triggers.

A safer control structure is:

python
production_trigger = definition["triggers"]

try:
    definition["triggers"] = {
        "manual": {
            "type": "Request",
            "kind": "Http",
            "inputs": {
                "schema": {
                    "type": "object",
                    "properties": {
                        "sample": {"type": "string"}
                    },
                    "required": ["sample"]
                }
            }
        }
    }

    result = mcp(
        "update_live_flow",
        environmentName=ENV,
        flowName=FLOW_ID,
        definition=definition,
        connectionReferences=connection_references
    )

    if result.get("error") is not None:
        raise RuntimeError(result["error"])

    FLOW_ID = FLOW_ID or result["created"]
    # Perform the approved test and validate all respon
...[truncated 534 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (17)

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 383)May include surrounding context.

Use resubmit_live_flow_run first. It works for EVERY trigger type — Recurrence, SharePoint, connector webhooks, Button, and HTTP. It replays the original trigger payload. Do NOT ask the user to manually trigger the flow or wait for the next scheduled run.

python

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file documents a SharePoint file upsert pattern that will create or overwrite files, and explicitly states that the flow ends with the latest content. The section explains how to perform the overwrite but does not warn users that the operation can replace existing document contents and affect stored data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This section documents updating SharePoint items via REST and highlights the IF-MATCH: * header, which bypasses conflict checks and overwrites regardless of the current ETag. While the mechanics are described, the markdown does not warn that this can clobber concurrent changes or alter data in another site without integrity safeguards.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 172)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 235)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 366)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 386)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 437)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-core.md (reported line 442)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/action-patterns-data.md (reported line 314)May include surrounding context.

md
"runAfter": {},
      "inputs": {
        "method": "GET",
        "uri": "https://api.example.com/customers/@{variables('customerId')}"
      }
    },
    "Compose_Email": {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The no-schema HTTP trigger example explicitly encourages accepting arbitrary JSON from external webhooks without validation or guardrails. In the context of a skill that scaffolds and deploys Power Automate flows, this can normalize insecure-by-default flow designs, increasing the chance that untrusted input is consumed by downstream actions, expressions, connectors, or data operations without validation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This markdown section describes sending email through Outlook, which can disclose user or system-generated content to external or internal recipients. The example provides the sending pattern but does not include any caution about verifying recipients, message content, or privacy implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This markdown file instructs users to write generated CSV output to files using CreateFile or UpdateFile, which can create or overwrite user data. The surrounding description explains how to perform the action but does not warn that it modifies stored files or may overwrite existing content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The file-change gate example explicitly says to "overwrite stored copy with new content" and recommends writing the new baseline before processing. That is a data-modifying operation with potential loss of prior baseline state, but the markdown does not include a warning about preserving previous versions or confirming overwrite expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The ConvertTimeZone section states that format string g produces a locale-specific short date/time and uses Taipei Standard Time as the destination timezone in the primary example. Because locale-sensitive formatting and timezone selection can affect user-visible output, presenting a fixed locale/timezone pattern without advising users to choose based on their own locale may violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The minimal example sets timeZone to AUS Eastern Standard Time, which imposes a specific regional locale in natural-language content. The policy for this audit flags language/locale constraints unless they are explicitly optional, user-chosen, or justified as region-specific; this example does not provide that context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The first recurrence example uses "AUS Eastern Standard Time" as the default timezone, which may implicitly steer users toward a specific locale. Although other timezone values are later listed, the example itself does not state that the locale is only illustrative or that users should select an appropriate timezone for their region.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.