azure-synapse-execute-as-via-library

Upload malicious library to a Spark pool (CanModifyCode) + the pool runs as the workspace MI (ExecutesAs) => execute code as the workspace MI. Cites can-execute-as.yaml execute-as-via-code-modify.

derived azure emits CanExecuteAs

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanModifyCode {'sparkPool': None} {'workspace': None} ExecutesAs {'mi': None} {'workspace': None} Contains {'sparkPool': None}

where

node_type(?sparkPool) == AnalyticsService node_type(?workspace) == AnalyticsService ?mi.privilege_level >= ?principal.privilege_level # escalation condition

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

{'principal': None} CanExecuteCommand {'sparkPool': None}

emit

source typeIdentity
target typeIdentity
source<principal>
target<workspace managed identity>
permissionsMicrosoft.Synapse/workspaces/bigDataPools/write
conditionstrigger_exists
state logicACTIVE if a run path exists (matched(optional[0]) — the principal can submit a Spark job — OR an existing trigger/scheduled session will run the pool); else CONDITIONAL(trigger_exists) — the malicious library is uploaded but awaits a job. Inherit weakest: if CanModifyCode is CONDITIONAL(service_state), this edge inherits that condition. If ?mi.privilege_level <= ?principal.privilege_level, do not emit.

Narrative

{principal.name} can upload a malicious library to Spark pool {sparkPool.name} (bigDataPools/write), which runs on Spark workers executing as workspace MI {mi.name}; triggering a session executes the library as {mi.name}.

Raw rule rules/derived/azure/synapse.yaml

id: azure-synapse-execute-as-via-library
emits: CanExecuteAs
description: Upload malicious library to a Spark pool (CanModifyCode) + the pool runs as the workspace
  MI (ExecutesAs) => execute code as the workspace MI. Cites can-execute-as.yaml execute-as-via-code-modify.
match:
- - principal: null
  - CanModifyCode
  - sparkPool: null
- - workspace: null
  - ExecutesAs
  - mi: null
- - workspace: null
  - Contains
  - sparkPool: null
where:
- node_type(?sparkPool) == AnalyticsService
- node_type(?workspace) == AnalyticsService
- '?mi.privilege_level >= ?principal.privilege_level  # escalation condition'
optional:
- - principal: null
  - CanExecuteCommand
  - sparkPool: null
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <workspace managed identity>
  permissions:
  - Microsoft.Synapse/workspaces/bigDataPools/write
  conditions:
  - trigger_exists
  state_logic: "ACTIVE if a run path exists (matched(optional[0]) \u2014 the principal can submit a Spark\
    \ job \u2014 OR an existing trigger/scheduled session will run the pool); else CONDITIONAL(trigger_exists)\
    \ \u2014 the malicious library is uploaded but awaits a job. Inherit weakest: if CanModifyCode is\
    \ CONDITIONAL(service_state), this edge inherits that condition. If ?mi.privilege_level <= ?principal.privilege_level,\
    \ do not emit."
  derived_from:
  - <CanModifyCode edge_id>
  - <ExecutesAs edge_id>
  - <Contains edge_id>
  - <CanExecuteCommand edge_id?>
  note: "CITES can-execute-as.yaml execute-as-via-code-modify. Dedupes on (CanExecuteAs, ?principal, ?mi)\
    \ \u2014 do not double-count weight when the generic rule also fires. The generic linchpin execute-as-via-code-modify\
    \ does NOT apply here because it checks node_class(?compute) == Compute; AnalyticsService is Data\
    \ class. This rule is the sole authoritative emitter for the library-injection path; there is no deduplication\
    \ with the generic linchpin. The match clause includes [ ?workspace, Contains, ?sparkPool ] to formalize\
    \ the parent-child relationship; this is a structural edge (not walked for attack paths) but required\
    \ to properly bind ?workspace from the CanModifyCode match. The escalation roll-up (CanEscalateTo)\
    \ is can-control.yaml escalate-via-execute-as \u2014 CITE, DO NOT re-derive."
  false_positive_note: "Emit only when the workspace MI out-privileges the principal (where guard). A\
    \ Spark pool with NO workspace MI yields no token loot; verify ExecutesAs exists. The library executes\
    \ only when a Spark session starts on the pool \u2014 ensure a trigger path exists for ACTIVE. Deny\
    \ assignment on bigDataPools/write -> CanModifyCode is BLOCKED -> this edge is BLOCKED."
  narrative: '{principal.name} can upload a malicious library to Spark pool {sparkPool.name} (bigDataPools/write),
    which runs on Spark workers executing as workspace MI {mi.name}; triggering a session executes the
    library as {mi.name}.'
move · open · esc close