Azure DevOps Variable Secret Not Secured
| Id | 4ca74dc0-8352-4ac5-893c-73571cc78331 |
| Rulename | Azure DevOps Variable Secret Not Secured |
| Description | Credentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as Secrets. This detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault. |
| Severity | Medium |
| Tactics | CredentialAccess |
| Techniques | T1552 |
| Kind | Scheduled |
| Query frequency | 1d |
| Query period | 1d |
| Trigger threshold | 0 |
| Trigger operator | gt |
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/ADOSecretNotSecured.yaml |
| Version | 1.0.4 |
| Arm template | 4ca74dc0-8352-4ac5-893c-73571cc78331.json |
let keywords = dynamic(["secret", "secrets", "password", "PAT", "passwd", "pswd", "pwd", "cred", "creds", "credentials", "credential", "key"]);
ADOAuditLogs
| where OperationName =~ "Library.VariableGroupModified"
| extend Type = tostring(Data.Type)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend VariableGroupName = tostring(Data.VariableGroupName)
| mv-expand Data.Variables
| where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)
| where Type != "AzureKeyVault"
| where Data_Variables !has "IsSecret"
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])
status: Available
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/ADOSecretNotSecured.yaml
triggerOperator: gt
description: |
'Credentials used in the build process may be stored as Azure DevOps variables. To secure these variables they should be stored in KeyVault or marked as Secrets.
This detection looks for new variables added with names that suggest they are credentials but where they are not set as Secrets or stored in KeyVault.'
kind: Scheduled
version: 1.0.4
tactics:
- CredentialAccess
entityMappings:
- fieldMappings:
- identifier: FullName
columnName: ActorUPN
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
entityType: Account
- fieldMappings:
- identifier: Address
columnName: IpAddress
entityType: IP
name: Azure DevOps Variable Secret Not Secured
triggerThreshold: 0
id: 4ca74dc0-8352-4ac5-893c-73571cc78331
queryPeriod: 1d
requiredDataConnectors: []
relevantTechniques:
- T1552
severity: Medium
queryFrequency: 1d
query: |
let keywords = dynamic(["secret", "secrets", "password", "PAT", "passwd", "pswd", "pwd", "cred", "creds", "credentials", "credential", "key"]);
ADOAuditLogs
| where OperationName =~ "Library.VariableGroupModified"
| extend Type = tostring(Data.Type)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend VariableGroupName = tostring(Data.VariableGroupName)
| mv-expand Data.Variables
| where VariableGroupName has_any (keywords) or Data_Variables has_any (keywords)
| where Type != "AzureKeyVault"
| where Data_Variables !has "IsSecret"
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])