Renamed GitHub Repos Inherit Azure's OIDC Trust
A Federated Identity Credential on an Azure Managed Identity keeps trusting a GitHub repository subject string long after that repository name is freed and reclaimed by an unrelated account. Azure AD's token exchange endpoint checks only the issuer, subject and audience tuple — not ownership continuity — so the new owner's workflow mints a valid OIDC token and inherits the identity's RBAC grants undetected.
At a glance
- Unsafe setting
- A Federated Identity Credential's subject claim is bound to a mutable GitHub org/repo name rather than an immutable repository ID.
- Failure trigger
- The original GitHub organisation or repository is renamed or deleted and the freed name is re-registered by a different account.
- Blast radius
- The new repository owner's Actions workflow mints an OIDC token matching the stale subject and exchanges it for the Managed Identity's Azure access token.
- Recommended control
- Pin trust to job_workflow_ref with a fixed commit SHA and audit federated credentials against GitHub's numeric repository_id, not display name.
The Trap
Federated Identity Credential subject binding to a GitHub repository by name rather than by its immutable repository ID.
The Default State
When you create a Federated Identity Credential on a User-Assigned Managed Identity or App Registration for GitHub Actions OIDC, the portal wizard writes the Subject identifier as repo:<org>/<repo>:ref:refs/heads/<branch> or repo:<org>/<repo>:environment:<name>. The Issuer is fixed at https://token.actions.githubusercontent.com and the Audience defaults to api://AzureADTokenExchange. Azure AD stores this as a static three-field tuple — issuer, subject, audience — and performs an exact string match against the sub, iss and aud claims presented in the client_assertion JWT during the OAuth2 exchange at /oauth2/v2.0/token. Nothing in that tuple references GitHub’s internal repository_id, and nothing re-validates ownership after the credential is created.
The Blast Radius
GitHub permits an organisation or repository name to be freed and immediately re-registered by an unrelated account the moment the original is renamed or deleted — a documented repojacking pattern. If your Federated Identity Credential still contains the old literal subject string, any new owner of that org/repo name — a different GitHub tenant, a separate business unit, or an external actor — can push a workflow run that mints an OIDC token with an identical sub claim. Azure AD’s token exchange endpoint has no visibility into GitHub’s repository lifecycle; it only checks the tuple match, so it issues a valid access token scoped to whatever role assignments the Managed Identity carries. The new owner inherits that RBAC, Key Vault access, or storage permission set, and Azure AD sign-in logs show nothing more suspicious than a routine federated token exchange from a trusted issuer.
The Lead Mechanic Fix
Audit every credential with az ad app federated-credential list –id <app-id> and cross-reference each subject string’s repository name against GitHub’s numeric repository_id via the REST API, not the display name. Where the workflow supports it, bind trust to the job_workflow_ref claim pinned to a specific reusable workflow path and commit SHA instead of a mutable branch ref, and scope Audience to a per-environment value rather than the shared default. Run a scheduled Azure Resource Graph query against federatedIdentityCredentials to flag any subject referencing a repository that no longer resolves under its original owner, and make credential removal a mandatory step in the repository transfer and deletion runbook, not an optional cleanup task.