AmyDocs

Security

Model

Amy's extension contains no credentials and no backend address. Each organization connects its own backend and keeps its AI provider credentials in its own secret store. The browser never receives, stores, displays or logs an AI credential.

Boundary Control
Extension → organization configuration Non-secret document in Azure DevOps extension data. Strict schema with unknown fields rejected; URL, HTTPS and trusted-hostname checks on every load; change history. Storage cannot restrict writers (see ADMIN-CONFIGURATION.md), so every user confirms the backend hostname before first use and after every change.
Extension → backend HTTPS. Metadata check without following redirects. Without a separate sign-in (AUTH_MODE=azure-devops), the user's Azure DevOps access token once per session, checked with Azure DevOps and discarded; with AUTH_MODE=entra, an Entra ID sign-in run by the backend. The session token is kept in the browser tab's sessionStorage until it expires (never localStorage or cookies), and discarded when the backend rejects it. Authorization and x-azdo-organization headers; no cookies (credentials: omit).
Extension → publisher's license service (Set up a backend) HTTPS, accepted only from the extension's origin (CORS). Amy's app token, signed with the extension's key; the organization's ID and name; the user's Azure DevOps access token, used once to ask Azure DevOps (connectionData) whether the user belongs to that organization under that ID, then discarded, never stored or logged. Pull-only registry access per organization; a revoked organization is never re-enabled there; at most one new password per organization every 10 minutes, and the previous one keeps working once.
Backend authentication Session token (HS256, SESSION_SIGNING_KEY): signature, issuer, audience (this API only), expiry and required claims. Azure DevOps token check: Azure DevOps itself confirms the user in the requested organization (connectionData); unauthenticated, anonymous and inactive identities are refused. At an Entra ID sign-in: ID token RS256 signature against the published keys, issuer, audience (the app's client ID), expiry, nonce, PKCE.
Backend authorization Allowed Azure DevOps organizations (membership verified with Azure DevOps when the session starts, and the header must match the session); with an Entra ID sign-in also allowed tenants and optional allowed users, groups or app role; enabled operations. A valid token alone is not enough. CORS is not used as authentication.
Organization isolation Usage counters, rate limits, concurrency, audit records and sign-in state are keyed by organization. The admin usage endpoint returns one organization at a time.
Backend → secrets Reference deployment: Key Vault (RBAC) references resolved by the App Service managed identity (Key Vault Secrets User, read-only). No Key Vault SDK; no secrets in IaC, pipelines or outputs.
Backend → AI provider HTTPS in production. The key is injected from validated configuration. Timeout and bounded retries. Upstream bodies are never logged or returned.
Extension → Azure DevOps User identity and documented scopes (PERMISSIONS.md). No PAT. Writes only after explicit confirmation.
Service hook → backend Shared secret in the x-amy-hook-secret header (compared in constant time, stored in Key Vault). Organization taken from the payload and checked against ALLOWED_ORGANIZATIONS. Completion is verified by reading the pull request again, never from the payload. Deliveries are deduplicated by event ID.
Backend → Azure DevOps (pull-request checks) The App Service managed identity, with read access to the enabled repositories and Wikis and permission to comment on pull requests. It never writes Wiki pages or work items.
Backend → Azure DevOps (Code with Amy) The same identity, on administrator-enabled repositories only: Read, Contribute, Create branch and Contribute to pull requests, plus View builds and Queue builds on the pipelines that validate pull requests. Only organization administrators and the teams they allow reach any of its routes, and a run starts only on repositories the requester can contribute to themselves (Git Repositories Contribute, from the repository's permissions and the requester's groups). Nothing is pushed before a person approves the plan, and only to branches under amy/code/, from the head it read; a target branch is never pushed to, and a pull request is never completed. What Amy writes runs in your pipelines before anyone reviews it, which is what validation pipelines do with any developer's branch. Its limits, enforced in code and not by the prompt: secrets files can't be read or changed; other secrets reach the model masked, and an edit is applied by exact quote only where the quote stands in the masked text too, so masked values can't be overwritten, read back or confirmed by guessing; text that looks like a secret isn't written; pipelines, agents' instructions and protected paths change only if the approved plan or the person names them, and the approval says so; .git and .amy never; commit messages can't skip pipelines. Files, documents, work items, review comments and logs are untrusted input to the model: it has no web access and no other way out than the pull request, which a person reviews and which says what changed outside the plan and which tests got weaker.
Backend → Azure DevOps (Repository Documentation) The same identity, on administrator-enabled repositories only (checked again when a job is created and estimated): Read, Contribute, Create branch and Contribute to pull requests. Pushes go only to branches under amy/docs/ and amy/dev-docs/, each from the branch head it read (a moved branch is refused, never overwritten); pull requests target the default branch, so its branch policies and the administrators' required reviewers apply, or for dev documents the dev branch, where administrators may choose no reviewers: those pull requests then complete by themselves once the dev branch's policies pass. Updates after merges and scheduled dev documents have no person behind them, so their checks read every enabled repository: enable only repositories that everyone who uses Amy may read. The service hook is authenticated by PR_DOCS_HOOK_SECRET, and what it says is confirmed by reading the pull request. Code is masked for secrets before it reaches the AI model, and every code quote the documentation keeps is checked against the file. Only administrators change the settings. A job starts only for repositories the requester can read themselves (Git Repositories Read, from the repository's permissions and the requester's groups), and its checks of findings against connected services read only enabled repositories the requester can read. Runs are visible to everyone with the Code tab; only who started one or an administrator can stop, discard or retry it or download its files.
Backend → Azure DevOps (Ask with search, Diagnose a Ticket) The same identity reads only the projects administrators chose and never the repositories they excluded, whatever the AI model asks for; secrets files are neither indexed nor read, and values that look like secrets are masked.
Mockups → browsers Versions open at /m/<token>/<file> without sign-in (192-bit random token; a link stops working when sharing is turned off or it expires), with MOCKUP_CSP (a sandbox: own scripts only, nothing loaded from elsewhere, nothing sent, no pop-ups or navigation), noindex and no-referrer. While Amy's designer works, the page runs in hidden sandboxed frames in the user's browser with the same rules as a meta tag, and no dialogs.
MCP client → backend Entra access token for this API (v2, RS256 against the published keys, issuer, audience, expiry, delegated scope Amy.Mcp), then the same tenant, organization, user, group and role policy as sessions. Azure DevOps is read with an on-behalf-of token for the user; no backend identity is used. Origins outside ALLOWED_ORIGINS are refused. Access by tab applies to each tool (the tab its feature is on), and a failed tool returns only messages written for people.
Stored proposals Keyed by organization. AI-client proposals are returned and decided only for their owner. A decision applies only to the revision the user reviewed (409 otherwise).

Reference backend controls

Reporting a vulnerability

Report vulnerabilities privately to contact@valor-co.com. Don't include credentials or content from your organization.

Review checklist (backend operators)