Skip to content

Proxy Stage 1 Azure DevOps reads without exposing SC_READ_TOKEN #1652

Description

@jamesadevine

Problem

permissions.read currently mints SC_READ_TOKEN from the configured ARM service connection and maps it into the Stage 1 Agent step as:

env:
  AZURE_DEVOPS_EXT_PAT: $(SC_READ_TOKEN)

This restores the documented ado-aw contract, but it also means the raw read-scoped ADO credential is visible inside the AWF sandbox. A prompt-injected agent with bash access can inspect or exfiltrate that token within the permitted network boundary.

The preferred long-term posture is the model used by gh-aw for tools.github.mode: gh-proxy: keep the real credential outside the agent container, expose a pre-authenticated CLI/HTTP path, and enforce read policy at a trusted proxy boundary.

Historical context

Reference architecture: gh-aw gh-proxy

Relevant gh-aw implementation:

The important properties are:

  1. The real GH_TOKEN is supplied to a host/trusted proxy, not the agent.
  2. AWF uses --exclude-env GH_TOKEN, preventing the raw token from reaching the agent container.
  3. The agent receives a pre-authenticated gh CLI path.
  4. Requests are routed through a policy-aware proxy that injects authentication and applies repository/integrity guards.
  5. Writes remain isolated behind safe outputs.

Proposed ado-aw direction

Introduce a trusted Azure DevOps CLI/REST proxy for Stage 1 reads.

Token flow

  1. permissions.read continues to mint SC_READ_TOKEN outside AWF via AzureCLI@2.
  2. The real token is passed only to a trusted proxy container/process.
  3. The Agent step does not receive SC_READ_TOKEN, AZURE_DEVOPS_EXT_PAT, SYSTEM_ACCESSTOKEN, or SC_WRITE_TOKEN.
  4. AWF explicitly excludes all ADO credential names from the agent container as defense in depth.
  5. Inside the sandbox, az devops receives a non-secret sentinel credential if needed to bypass client-side login checks; the proxy strips that header and injects the real bearer upstream.

Request routing

  • Attach the proxy as a trusted AWF topology endpoint, analogous to MCPG/gh-aw's CLI proxy.
  • Route Azure DevOps API traffic from az devops, curl, and SDK clients through the proxy.
  • Prevent direct Stage 1 egress to ADO API hosts when proxy mode is active, otherwise an agent could bypass policy enforcement.
  • Maintain an explicit upstream host allowlist (dev.azure.com, vssps.dev.azure.com, and any additional ADO hosts proven necessary).

Read policy

A method-only policy is insufficient because Azure DevOps has read-like POST endpoints such as WIQL and batch-query APIs. The proxy needs a route-aware allowlist that classifies allowed read operations by normalized method + route.

Policy requirements:

  • Fail closed for unknown routes, methods, API versions, or hosts.
  • Permit only documented read operations required by supported Stage 1 tooling.
  • Reject every mutating operation before forwarding.
  • Normalize organization/project/resource path segments before matching.
  • Bound request/response sizes and timeouts.
  • Never log authorization headers, tokens, or unsanitized sensitive payloads.

The backing service connection should still be provisioned read-only. Proxy policy and identity permissions provide defense in depth; neither should be the sole control.

Existing related surface

The Azure DevOps MCP already keeps ADO_MCP_AUTH_TOKEN in the MCPG child rather than the Agent process. This issue concerns the broader direct CLI/REST surface (az devops, curl, language SDKs) that currently requires AZURE_DEVOPS_EXT_PAT in Stage 1.

Feasibility questions

  1. Can AWF's existing cli-proxy sidecar be generalized for Azure DevOps, or should ado-aw ship a dedicated proxy through ado-script/MCPG?
  2. Can az devops reliably use HTTPS_PROXY plus a sentinel AZURE_DEVOPS_EXT_PAT, including TLS CA injection inside the AWF container?
  3. Which ADO hosts and redirects are required for Azure DevOps CLI read operations?
  4. What is the minimum route catalog for repositories, builds, work items, identities, and search?
  5. How should cross-project/cross-organization reads be represented and constrained?
  6. Should proxy mode become automatic for every permissions.read, or begin as an opt-in migration mode?
  7. How do we version the route policy so newly introduced Azure DevOps endpoints fail visibly rather than silently broadening access?

Acceptance criteria

  • A workflow with permissions.read can run az devops project list and supported read-only REST calls inside AWF without the real ADO token being present in the agent environment, files, argv, /proc, or logs.
  • SC_READ_TOKEN, SC_WRITE_TOKEN, SYSTEM_ACCESSTOKEN, and the real AZURE_DEVOPS_EXT_PAT are absent from Agent and Detection containers.
  • Detection receives no ADO access path or credential.
  • Direct Stage 1 ADO API egress cannot bypass the proxy.
  • Supported reads succeed through a route-aware allowlist.
  • Representative writes through az devops, raw HTTP, and SDK clients are rejected by the proxy and produce no ADO mutation.
  • Unknown routes/methods fail closed with actionable diagnostics.
  • Proxy logs are auditable and sanitized.
  • Standalone, 1ES, job, and stage targets emit the same credential boundary.
  • Deterministic compiler tests assert token exclusion, proxy wiring, and Detection isolation.
  • A live AgentPlayground smoke proves authenticated reads and deliberate write rejection without relying solely on model interpretation.
  • Documentation explains the proxy trust boundary, route policy, service-connection requirements, and migration behavior.

Non-goals

  • Replacing Stage 3 safe-output authorization.
  • Giving the Agent any write-capable ADO identity.
  • Proxying general Azure Resource Manager or Microsoft Graph operations.
  • Treating a single denied no-op write as proof that an identity is globally read-only.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions