azure-sql-database-export-exfiltrate
databases/export/action exports the full DB as a BACPAC to a caller-specified storage URL, enabling complete data exfiltration outside the tenant.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?database) ==
RelationalDatabase
?database.provider_type == 'Microsoft.Sql/servers/databases'
?principal has EFFECTIVE Microsoft.Sql/servers/databases/export/action at ?database scope (Owner, Contributor, SQL DB Contributor 9b7fa17d-e63e-47b0-bb0a-15c516ac86ec, or custom role with export/action)
emit
| source type | Identity |
|---|---|
| target type | RelationalDatabase |
| source | ?principal |
| target | ?database |
| permissions | Microsoft.Sql/servers/databases/export/action |
| conditions | iam_permission |
| state logic | if a deny assignment or deny Azure Policy covers databases/export/action at the effective scope: BLOCKED; else ACTIVE: the principal can immediately invoke the export REST API (POST /databases/{db}/export) supplying a caller-controlled storage URI and access key/SAS token. The export is asynchronous but completes without further confirmation from the data owner. Network note: databases/export/action is an ARM control-plane call; it is NOT gated by the SQL server firewall. The export job itself connects internally (Azure fabric); the BACPAC lands in the caller-specified storage account. |
Narrative
{principal.name} holds databases/export/action on {database.name}, allowing it to export the complete database (schema and all data) as a BACPAC file to a caller-specified Azure Blob Storage location. The export bypasses the SQL firewall and completes asynchronously, enabling full data exfiltration to any storage account the attacker controls.
Raw rule rules/derived/azure/sql.yaml
id: azure-sql-database-export-exfiltrate
emits: CanExfiltrate
description: databases/export/action exports the full DB as a BACPAC to a caller-specified storage URL,
enabling complete data exfiltration outside the tenant.
match:
- - principal: null
- HasPermission
- database: null
where:
- node_type(?database) == RelationalDatabase
- ?database.provider_type == 'Microsoft.Sql/servers/databases'
- ?principal has EFFECTIVE Microsoft.Sql/servers/databases/export/action at ?database scope (Owner, Contributor,
SQL DB Contributor 9b7fa17d-e63e-47b0-bb0a-15c516ac86ec, or custom role with export/action)
emit:
source_type: Identity
target_type: RelationalDatabase
source: ?principal
target: ?database
permissions:
- Microsoft.Sql/servers/databases/export/action
conditions:
- iam_permission
state_logic: 'if a deny assignment or deny Azure Policy covers databases/export/action at the effective
scope: BLOCKED; else ACTIVE: the principal can immediately invoke the export REST API (POST /databases/{db}/export)
supplying a caller-controlled storage URI and access key/SAS token. The export is asynchronous but
completes without further confirmation from the data owner. Network note: databases/export/action
is an ARM control-plane call; it is NOT gated by the SQL server firewall. The export job itself connects
internally (Azure fabric); the BACPAC lands in the caller-specified storage account.'
confidence: '0.95'
derived_from:
- <HasPermission edge_id (databases/export/action)>
false_positive_note: "SQL Server Contributor (6d8ee4ec) does NOT include databases/export/action \u2014\
\ verify effective permissions explicitly; do not infer from the role name alone. Owner and Contributor\
\ at subscription/RG scope DO include it. SQL DB Contributor (9b7fa17d) at the database scope includes\
\ it. Custom roles must explicitly list export/action. The export is an ARM call; the SQL server firewall\
\ rules and private endpoint configuration do NOT block it \u2014 the exfiltration happens regardless\
\ of network exposure settings. The target of CanExfiltrate is the SQL Database (RelationalDatabase\
\ node); the landing storage account is modeled as the write destination separately if it is in scope.\
\ This rule only applies to Azure SQL Database (Microsoft.Sql/servers/databases); SQL MI uses a different\
\ backup/export model (LTR backup to storage) \u2014 see separate rule if warranted."
narrative: '{principal.name} holds databases/export/action on {database.name}, allowing it to export
the complete database (schema and all data) as a BACPAC file to a caller-specified Azure Blob Storage
location. The export bypasses the SQL firewall and completes asynchronously, enabling full data exfiltration
to any storage account the attacker controls.'