You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -65,6 +65,11 @@ Every Azure Pipelines job automatically gets an OAuth token via `$(System.Access
65
65
### ⚠️ Advanced Security Impact
66
66
As of **Sprint 269**, build service identities can no longer call Advanced Security APIs. A temporary rollback is in effect **until April 15, 2026**, after which `System.AccessToken`**will not work** for Advanced Security REST API calls.
67
67
68
+
### Important: Access Model for System.AccessToken
69
+
70
+
-**Script steps** (PowerShell, Bash inline): require explicit `env: SYSTEM_ACCESSTOKEN: $(System.AccessToken)` mapping or the "Allow scripts to access the OAuth token" job setting enabled
71
+
-**Pipeline tasks/extensions**: can access the token via the Task SDK (`SYSTEMVSSCONNECTION` endpoint) without any user opt-in — see [Section 14](#14-why-microsoft-removed-build-identity-access--security-analysis) for security implications
This section explains the security rationale behind Microsoft's Sprint 269 decision to block build service identities from Advanced Security APIs. The findings below are based on verified technical analysis of the Azure Pipelines Task SDK, Microsoft documentation, and actual marketplace extension source code.
994
+
985
995
### The Security Risk (Confirmed)
986
996
987
-
**Your intuition is correct.**Prior to Sprint 269, any pipeline running with `System.AccessToken` could read Advanced Security alerts because the Build Service identity had **implicit API access by default**. This created a real security risk:
997
+
Prior to Sprint 269, any pipeline running with `System.AccessToken` could read Advanced Security alerts because the Build Service identity had **implicit API access by default**. This created a critical security risk:
988
998
989
999
```
990
-
Risk Chain:
991
-
Any pipeline task/extension (including marketplace)
992
-
→ Accesses System.AccessToken (tasks get it automatically)
993
-
→ Authenticates as Build Service identity
1000
+
Attack Chain:
1001
+
Any installed pipeline task/extension (including marketplace)
|`tl.getEndpointAuthorizationParameter('SYSTEMVSSCONNECTION', 'AccessToken', false)`|**Any pipeline task** via the Task SDK | ❌ **No** — built-in system endpoint, always available | 🔴 Critical |
1016
+
|`tl.getVariable('System.AccessToken')`|**Any pipeline task** via the Task SDK | ❌ **No** — pipeline variables are accessible to tasks | 🔴 Critical |
1017
+
|`process.env['SYSTEM_ACCESSTOKEN']`|**Scripts** (inline bash/PS) | ✅ **Yes** — requires `env: SYSTEM_ACCESSTOKEN: $(System.AccessToken)` or "Allow scripts to access OAuth token" | 🟡 Medium |
1018
+
1019
+
**Key finding**: `SYSTEMVSSCONNECTION` is a **built-in system service endpoint** that Azure Pipelines exposes to every task in every job. It represents the Build Service identity. Any pipeline task — including marketplace extensions — can call `tl.getEndpointAuthorizationParameter('SYSTEMVSSCONNECTION', 'AccessToken', false)` to obtain the OAuth token **without any user configuration or opt-in**.
1020
+
1021
+
The "Allow scripts to access the OAuth token" setting **only applies to script steps** (inline PowerShell, Bash, CMD). It does **NOT** restrict task-level access via the Task SDK. This distinction is often misunderstood.
1000
1022
1001
-
1.**Build Service had default access**: The `Project Collection Build Service` and project-scoped Build Service identities were allowed to call Advanced Security APIs by default — no explicit permission grant was needed.
-**Pipeline Tasks/Extensions**: can access the job access token as part of their normal operation via the Task SDK, without the user explicitly mapping it
1025
+
A marketplace extension does NOT need to declare any special permissions or service connection inputs to access the Build Service token. The task code simply needs:
1026
+
1027
+
```typescript
1028
+
import*astlfrom'azure-pipelines-task-lib/task';
1029
+
1030
+
// No user opt-in, no service connection input, no special permission
**Verified by source code analysis**: Popular marketplace extensions (e.g., token replacement, code analysis, deployment tools) typically do NOT access `SYSTEMVSSCONNECTION` or call ADO REST APIs beyond their stated purpose. However, **nothing in the platform prevents them from doing so** — there is no sandboxing, no API allowlist per extension, and no runtime permission gate.
1043
+
1044
+
### Three Compounding Factors
1045
+
1046
+
**Factor 1: Shared Identity — No Pipeline Isolation**
1047
+
1048
+
The Build Service identity (`Project Collection Build Service` or `{Project} Build Service`) is **shared across ALL pipelines** in a project (or the entire collection if not restricted). Every task in every pipeline gets the same identity with the same permissions.
1049
+
1050
+
> From [Microsoft Learn](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/access-tokens): *"The permissions of this token are based on the Project Build Service identity, meaning all job access tokens in a project have identical permissions."*
1051
+
1052
+
**Factor 2: Advanced Security API Access Was Not Explicitly Gated**
1053
+
1054
+
Prior to Sprint 269, Build Service identities were **not blocked at the API level** from calling Advanced Security endpoints. The [Sprint 269 release notes](https://learn.microsoft.com/en-us/azure/devops/release-notes/2026/ghazdo/sprint-269-update) confirm this was the change: *"Advanced Security REST APIs no longer accept build service identities."* The [rollback blog](https://devblogs.microsoft.com/devops/temporary-rollback-build-identities-can-access-advanced-security-read-alerts-again/) further states the restriction was *"a security improvement"* that was rolled back because customers relied on this access for automation. This means pipelines using `System.AccessToken` could call the Advanced Security API without any administrator having explicitly granted `Advanced Security: Read alerts` to the Build Service.
1055
+
1056
+
**Factor 3: No Extension Sandboxing**
1057
+
1058
+
Azure DevOps does not sandbox pipeline task execution. A task runs as a Node.js process on the agent with full access to:
1059
+
- The `SYSTEMVSSCONNECTION` token
1060
+
- The agent's file system (build sources, artifacts, secrets on disk)
1061
+
- Outbound network access (can exfiltrate data)
1062
+
- All environment variables set by previous tasks
1063
+
1064
+
### The Risk: Supply-Chain Attacks on Marketplace Extensions
1065
+
1066
+
The combination of these three factors creates a supply-chain attack vector:
1067
+
1068
+
```
1069
+
1. Attacker publishes (or compromises) a popular marketplace extension
1070
+
2. Extension update adds code to read SYSTEMVSSCONNECTION token
1071
+
3. Extension calls Advanced Security API to harvest vulnerability data
1072
+
4. Extension exfiltrates: which repos have unpatched CVEs, exposed secrets, code vulnerabilities
1073
+
5. Attacker uses this intelligence to target the organization's weakest points
1074
+
```
1006
1075
1007
-
3.**Shared identity problem**: The Build Service identity is **shared across ALL pipelines in a project** (or the entire collection if not restricted). There's no per-pipeline isolation. Any task in any pipeline gets the same identity.
1076
+
This is not theoretical — Microsoft's own pipeline security guidance explicitly warns:
> *"This change prevents pipeline-based automation from accessing or modifying security alert data using build service accounts, reducing the risk of unintended alert state changes during CI/CD runs."*
1078
+
> From [Microsoft Learn - Secure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/security/misc): *"If a malicious actor gains pipeline access in one project, and Build Service identities are insufficiently scoped, they could affect other projects' resources — escalating an initially limited breach into a wider compromise."*
1011
1079
1012
-
5.**The fix**: Microsoft is requiring a **named service principal** with explicit `Advanced Security: Read alerts` permission, which provides:
1013
-
- Explicit, auditable identity (not a shared build account)
- Per-pipeline access control via service connections
1080
+
### Microsoft's Stated Reasoning (Sprint 269)
1017
1081
1018
-
### Is a Simple Extension a Risk?
1082
+
From the [Sprint 269 release notes](https://learn.microsoft.com/en-us/azure/devops/release-notes/2026/ghazdo/sprint-269-update):
1019
1083
1020
-
**Yes.** A marketplace extension (or any custom task) installed in the organization:
1021
-
- Runs with the job's access token automatically (tasks access it via the Task SDK)
1022
-
- Does NOT need "Allow scripts to access the OAuth token" — that setting only applies to script steps, not task steps
1023
-
- Could call any API the Build Service identity has access to
1024
-
- Before Sprint 269, that included Advanced Security APIs
1084
+
> *"Advanced Security REST APIs no longer accept build service identities (such as `Project Collection Build Service`) as callers. This change prevents pipeline-based automation from accessing or modifying security alert data using build service accounts, reducing the risk of unintended alert state changes during CI/CD runs."*
1025
1085
1026
-
**This is precisely why Microsoft made the Sprint 269 change** — to ensure that only explicitly authorized service principals (with audit trails and conditional access) can read security alert data, not any pipeline task running under the broadly-shared Build Service identity.
1086
+
From the [temporary rollback blog post](https://devblogs.microsoft.com/devops/temporary-rollback-build-identities-can-access-advanced-security-read-alerts-again/):
1087
+
1088
+
> *"We restricted API access for build identities as a security improvement but failed to provide an early notice for customers that relied upon this for various automations."*
1089
+
1090
+
### How a Service Principal Fixes This
1091
+
1092
+
Moving to a dedicated Service Principal with an Azure DevOps Service Connection resolves all three compounding factors:
1093
+
1094
+
| Factor | Build Service (old) | Service Principal (new) |
| Service Principals & Managed Identities in ADO |https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity|
1037
1112
| Authenticate with Entra ID |https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/entra|
1113
+
| Service Principals & Managed Identities in ADO |https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity|
| Configure Advanced Security Features & Status Checks |https://learn.microsoft.com/en-us/azure/devops/repos/security/configure-github-advanced-security-features|
1044
1120
| Author a Pipeline Decorator |https://learn.microsoft.com/en-us/azure/devops/extend/develop/add-pipeline-decorator|
0 commit comments