azure-auto-exposes-runas-cred
An Automation Account with a legacy RunAs account exposes the RunAs service principal certificate to any runbook via Get-AutomationConnection.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?account) ==
AutomationService
node_type(?runasConn) == Certificate
?runasConn is of connection type AzureServicePrincipal with CertificateThumbprint field (RunAs account)
emit
| source type | GenericCompute |
|---|---|
| target type | ApplicationIdentity |
| source | <runbook (BuildWorker) in ?account> |
| target | <RunAs service principal (ApplicationIdentity)> |
| conditions | trigger_exists |
| state logic | ACTIVE when the account contains a RunAs Connection of type AzureServicePrincipal with CertificateThumbprint (ContainsSecret confirmed) and a runbook can execute in the sandbox. CONDITIONAL(trigger_exists) if no confirmed run path exists. BLOCKED if the RunAs account has been removed. |
Narrative
Automation Account {account.name} has a legacy RunAs connection; any runbook can call Get-AutomationConnection to retrieve the RunAs SP certificate and authenticate as the RunAs service principal {target.name} without holding the SP's client secret in ARM RBAC.
Raw rule rules/derived/azure/automation.yaml
id: azure-auto-exposes-runas-cred
emits: ExposesCredential
description: An Automation Account with a legacy RunAs account exposes the RunAs service principal certificate
to any runbook via Get-AutomationConnection.
match:
- - account: null
- ContainsSecret
- runasConn: null
where:
- node_type(?account) == AutomationService
- node_type(?runasConn) == Certificate
- ?runasConn is of connection type AzureServicePrincipal with CertificateThumbprint field (RunAs account)
emit:
source_type: GenericCompute
target_type: ApplicationIdentity
source: <runbook (BuildWorker) in ?account>
target: <RunAs service principal (ApplicationIdentity)>
permissions: []
conditions:
- trigger_exists
state_logic: ACTIVE when the account contains a RunAs Connection of type AzureServicePrincipal with
CertificateThumbprint (ContainsSecret confirmed) and a runbook can execute in the sandbox. CONDITIONAL(trigger_exists)
if no confirmed run path exists. BLOCKED if the RunAs account has been removed.
confidence: 0.95
derived_from:
- 'ContainsSecret: ?account stores RunAs Connection (Certificate)'
- 'credential-chains.yaml: ExposesCredential + CredentialsFor(RunAs cert -> SP) => CanImpersonate'
false_positive_note: The RunAs certificate private key is NOT returned via ARM `connections/read`; it
is only accessible from within a runbook via `Get-AutomationConnection`. This edge therefore only
materializes when an attacker can execute code in the sandbox (combined with a CanModifyCode or CanTrigger
edge). Do not emit as a standalone credential read from ARM. Verify the connection type is AzureServicePrincipal
with a CertificateThumbprint field (the RunAs pattern); a non-RunAs connection is not this threat.
RunAs accounts are deprecated; check for their presence explicitly.
narrative: Automation Account {account.name} has a legacy RunAs connection; any runbook can call Get-AutomationConnection
to retrieve the RunAs SP certificate and authenticate as the RunAs service principal {target.name}
without holding the SP's client secret in ARM RBAC.