//Azure DevOps - Security Testing Guide (Ado-STG)/Pipeline Injection
| ID: | AdoSTG-PI-01, AdoSTG-PI-02, AdoSTG-PI-03, AdoSTG-PI-04 |
This section describes how a tester can check if it's possible to abuse variables, parameters, macros, and templates in pipelines to gain code execution.
The main difference between variables and parameters is evaluation.
Evaluation is syntax-dependent. Variables defined with macro syntax ('$(var)') evaluate at runtime before a task runs and are used in scripts and tasks. Variables defined with runtime expressions ('$[variables.var]') evaluate before a job or stage runs and are used in conditions or dynamic variable assignment.
To test for this, examine the pipeline definition for compile-time template expressions ${{ }}. If these are in the form of parameters, then they might be user-controlled and can be used for code injection in the pipeline.
Check if variables can come from a PR context; for this to be the case, "variables." need to be used in the pipeline, and these must not be system-safe variables, i.e., not user-controlled. A list of these is presented below:
0"Build_BuildId", 1"Build_BuildNumber", 2"Build_Repository_Name", 3"Build_Repository_Uri", 4"Build_SourceVersion", 5"Build_DefinitionName", 6"System_TeamProject", 7"System_CollectionUri", 8"System_DefinitionId", 9"System_TeamProjectId", 10"System_CollectionId", 11"System_HostType", 12"System_JobId", 13"System_PlanId", 14"System_StageId", 15"System_PhaseId", 16"System_TimelineId", 17"System_TaskInstanceId", 18"System_JobDisplayName", 19"System_StageDisplayName", 20"Agent_BuildDirectory", 21"Agent_Id", 22"Agent_MachineName", 23"Agent_Name", 24"Agent_OS", 25"Agent_OSArchitecture", 26"Agent_TempDirectory", 27"Agent_ToolsDirectory", 28"Agent_WorkFolder", 29"Agent_JobName", 30"Pipeline_Workspace",
This issue contains parameters and variables that are used together with runtime expressions $[ ]; if this is the case and the runtime user expression is user-controlled, then the user can inject untrusted code into the pipeline.
To check for this, look for runtime expressions $[ ] and "parameters." or "variables."
To check for this issue:
$(VarName) are ised in the pipeline.0"Build.BuildId", 1"Build.BuildNumber", 2"Build.SourceVersion", 3"Build.SourceVersionMessage", 4"Build.Repository.Name", 5"Build.Repository.Uri", 6"Build.DefinitionName", 7"Build.Reason", 8"System.TeamProject", 9"System.CollectionUri", 10"System.DefinitionId", 11"System.TeamProjectId", 12"System.CollectionId", 13"System.HostType", 14"System.JobId", 15"System.PlanId", 16"System.StageId", 17"System.PhaseId", 18"System.TimelineId", 19"System.TaskInstanceId", 20"System.JobDisplayName", 21"System.StageDisplayName", 22"Agent.BuildDirectory", 23"Agent.Id", 24"Agent.MachineName", 25"Agent.Name", 26"Agent.OS", 27"Agent.OSArchitecture", 28"Agent.TempDirectory", 29"Agent.ToolsDirectory", 30"Agent.WorkFolder", 31"Agent.JobName", 32"Pipeline.Workspace"
This section shows how this issue can be exploited.
The minimum privileges to execute this attack, given a vulnerable build definition was found, are:
Edit queue build configuration and Queue builds
For standard code injection, the user can add the command to be injected into the vulnerable variable.
A vulnerable .yaml file might look like this:
0trigger: 1- main 2pool: 3 vmImage: ubuntu-latest 4steps: 5- script: | 6 echo $(InjectionPoint) 7 displayName: 'Use variable to perform code injection'
Using a standard code injection such as && whoami produces the following:
0Condition evaluation 1Starting: Use variable to perform code injection 2============================================================================== 3Task : Command line 4Description : Run a command line script using Bash on Linux and macOS and cmd.exe on Windows 5Version : 2.279.0 6Author : Microsoft Corporation 7Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/command-line 8============================================================================== 9[Host] Selected Node version: Node24 (Strategy: Node24Strategy) 10Generating script. 11Script contents: 12echo && whoami 13========================== Starting Command Output =========================== 14/usr/bin/bash --noprofile --norc /home/vsts/work/_temp/268acd86-4744-46ab-8373-471b0118bae6.sh 15vsts 16Finishing: Use a variable to perform code injection
Use an environment variable instead of direct parameter interpolation in scripts. Set the parameter as an env var and reference it safely.
Avoid using variables directly in scripts, as they may come from PR context. Use environment variables with validation instead.
Runtime expressions with parameters or variables can be exploited. Use environment variables with validation instead of runtime expressions in scripts.
Macro expression references an injectable variable. Use an environment variable instead of direct macro interpolation in scripts.