Prefer no secret at all, using service connections or managed identities. If you need one, Microsoft recommends Azure Key Vault, because Azure role-based access control can limit who reads it. Variable groups and pipeline secret variables work too, with different scoping. Never put a secret as plain text in YAML.
Options compared
| Where | Who can see it | Strength | Watch out for |
|---|---|---|---|
| No secret (service connection, managed identity) | Nobody holds a value | Nothing to leak | Not available for every target |
| Azure Key Vault | Controlled with Azure RBAC | Central, auditable, per secret control | Pipeline identity needs read access |
| Variable group | Follows library security roles | Shared by several pipelines | Group permissions decide who can use it |
| Pipeline secret variable | Users of that pipeline only | Simple, scoped to one pipeline | Not shared, easy to forget |
Rules from Microsoft's guidance
- Do not use a logging command to set a secret variable, because anyone with pipeline access can then see it.
- Do not echo secrets and do not pass them on the command line. Map them into environment variables instead.
- Do not wrap secrets in JSON, XML, or YAML blobs, or include control characters such as line feeds. Create one secret per value so redaction works.
- Azure Pipelines tries to scrub secrets from logs, but is not foolproof. Review logs after testing valid and invalid inputs, since error output can leak.
- Be careful with Azure CLI commands that print sensitive output. Use the None output format.
Limiting secrets to one branch
Microsoft describes a combination. Enforce build validation policies that allow builds only from a certain branch. Use variable group permissions so only authorized pipelines can read the group. Then use a condition so only a push to the designated branch can reference the group, for example by checking that the source branch is refs/heads/main.
This matters because a pull request pipeline that can read a production secret hands that secret to anyone who can open a pull request. See fork builds.
Rotation and review
- Periodically list the secrets registered in your pipelines and delete the ones no longer needed.
- Check that service connection secrets are handled carefully.
- Keep PAT duration short and scopes minimal.
- Rotate secrets on a schedule, so a leaked one has a short useful life.
- Review pipeline source and tasks to confirm secrets are not sent to unintended hosts.
Templates help
Instead of inline scripts that take secret parameters, keep the script in a template in a separate, secure repository and pass the secret as a parameter from Key Vault, a variable group, or the pipeline UI. This keeps secret handling in one reviewed place.
A quick decision
Ask three questions in order. Can the pipeline authenticate without a secret? If not, can Key Vault hold it? If not, can a variable group with restricted permissions hold it? Only then use a pipeline level variable.
Quick check
Are masked secrets always hidden in logs?
No. Microsoft says scrubbing is attempted but is not foolproof, so avoid echoing secrets and review logs.
Why one secret per value?
Structured data such as JSON can defeat redaction. Separate secrets are redacted more accurately.
Safeguard can scan repositories and dependencies as part of a pipeline, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.