I am in your pipeline reading all your secrets!


With this blog post I want to raise awareness and understanding on how secure / marked as secret variables are handled during pipeline runtime in Azure DevOps and how these can be potentially exfiltrated. If proper security configuration is not in place this could potentially be abused by attackers.

Lets move ahead to create different types of variables and try to retrieve their values. By doing so at the end of this blog post it will be clear why it’s not very sensible to give all project team members full access to pipelines. And why in some cases it’s better to set-up private build agents.

Available variables

Currently Azure DevOps support the following ways to deal with variables.

  • Write variables inline inside the YAML - Inline variables
  • Set variables when starting a pipeline run - Queue time variables
  • Set variables during pipeline creation - Pipeline variables
  • Store variables in variable groups - Library group variables
  • Link Key Vault to a variable group - Key Vault linked variables

Since access to git repositories is considered standard for a user with contributor permissions and queue time variables only exists for a single run it does not make much sense to demonstrate these two types. Next step is to create the remaining four types.

Creating variables

To create all four mentioned variables we are going to use an account with project administrator permissions. Making sure we are creating everything from an administrator perspective.

Pipeline variables

First the pipeline variables. These variables are set during creation or editing of a pipeline. Either on an existing pipeline or for a new one we can simply click on the variables button to bring the variable window up and click on New Variables as shown in the following images.

New pipeline variables button

For this example the following variable is added and marked as secret.

New pipeline variables

Library group variables

Library group variables are part of a variable group. Simply create a variable group by clicking on Variables and then +Variable group.

For this example the following variable is added and again marked as secret.

Library group variables

Key Vault linked pipeline variables

Basically this is the same set-up as the regular library group variables but this library group is linked with Key Vault. Meaning that selected Key Vault values can be managed in a Key Vault while used via the variable group in question.

For this example I have created two variables inside a demo Key Vault and linked them to the variable group as follows.

Two Key Vault secrets
Key Vault variable group

Runtime magic

To try and read the variables we are going to switch to a project contributor user. This user has the regular out of the box project contributer permission but with a bit stricter variable group permissions. The two variable groups used in the previous steps have had their permissions changed so that project contributers don’t have access to these groups. In the following image the difference in permission to variable groups is shown.

Variable groups permission

So from a project contributor perspective prior to be able to read any variables we need to first find out which groups with which variables are present within the project. This can be done by calling the Azure DevOps API from within a pipeline as within the pipeline we can use the SYSTEM_ACCESSTOKEN of the project or even the project collection Build Service. This service is used during pipeline runtime so by default it has quite a large number of permissions. The script to get what we need looks als following.

Result of this script looks as follows.

All variable group secrets

Looking at the script output we can see that the variable group my-demojev-vars contains a marked as secret (“isSecret”: true) variable called very-secret-secret and that the variable group my-shuttle-kv-vars has test-keyvault-secret one and two variables marked as secret.

Variable values of variables which are not marked as secret are already visible by simply calling this api without doing anything special. Don’t worry their values are not real.

Retrieving secret values

To retrieve the marked as secret (“isSecret”: true) values we must make sure that the variable groups are referenced inside the pipeline. Then its simply just converting the values to Base64 encoded strings to bypass the pipeline output GUI and doing a write-output on each of them. It would of course also be possible to send the values to other places like an API or a storage account directly from the pipeline.

First add both variable groups to the pipeline in question

Then add the following two lines for each variable into an in-line PowerShell pipeline task.

Final result of a full pipeline would look as follows.

When the above pipeline is executed the pipeline output will contain the Base64 encoded strings for each of the variable values. As show in the following clipping.

Pipeline output

The only thing that remains is to convert the Base64 encoded strings back to see the values. This can be done using the following PowerShell script

Looking at the following image with the decoded results the secured / marked as secret variable values and of course regular variable values to which developers don’t have access to can still be retrieved by combining pipeline access with 50ish lines of PowerShell.

Decoded results

Wrapping up

Often organizations are hyper focused strict rules and policies for access to key’s and secrets, unfortunately only focusing on one part of a supply chain is as shown with this example is no longer a sufficient strategy.

If after reading this post you are still wondering what potential harm can be done with all the information exposed trough reading variables in runtime, then please also read my previous blog post on this subject Hacking Azure DevOps . Otherwise please use this blog post to double check your Azure DevOps pipeline and variable group security configuration.
Thank you for taking the time to read this post!