Sub:jugation – Hijacking Cloud Identities by Recycling Namespaces in Global OIDC Issuers
Executive Summary
Astrix Security Research has discovered a new vulnerability class affecting GitHub Actions, GitLab CI, and Terraform Cloud, which we’re calling “Sub:jugation“. By abusing the global OIDC issuer model that all three platforms share, an attacker can assume cloud IAM roles that were configured by (and intended for) entirely different organizations and repositories.
The root cause is deceptively simple: all CI/CD platforms each issue OIDC tokens from a single, global endpoint shared across every tenant on the platform. When a repository is deleted, a username is changed, or a namespace is recycled, the OIDC sub (subject) claim tied to that repository becomes reclaimable by anyone. Any attacker who re-creates a repository with the same path gets OIDC tokens with the identical subject — and can assume any cloud IAM role that still trusts it.
We call these forgotten IAM roles Phantom Cloud Identities: they linger silently in your cloud environment, patiently waiting for anyone who can produce a matching token. And producing one requires nothing more than creating a GitHub repository.
We have reported this vulnerability to affected CI platforms such as GitHub Actions, Gitlab CI and HCP Terraform Runs and are disclosing it in coordination with their respective security teams.
Background – What is OIDC and How GitHub Actions Access Your Cloud
Modern CI/CD pipelines frequently need access to resources in cloud environments like AWS, GCP and Azure: accessing virtual machines, deploying and pushing images, or reading secrets and configurations. For years, the only way to do this was to store long-lived cloud credentials (such as access keys or service account JSON files) as repository secrets. The problem is obvious: static credentials are a massive target, they rarely get rotated, and a single secret leak can compromise production.
OIDC (OpenID Connect) was proposed as the clean solution to this problem. Instead of storing credentials, the CI/CD platform acts as an identity provider. When a workflow runs, it requests a short-lived, signed JWT directly from the platform. The cloud provider is pre-configured to trust the CI/CD platform and when presented with the JWT, verifies the token’s signature and exchanges it for temporary cloud credentials.
For GitHub Actions, the flow looks like this:
- A GitHub Actions workflow requests an OIDC token from https://token.actions.githubusercontent.com
- GitHub signs a JWT with claims about the workflow. The most important one is the sub claim which contains the repository name, branch, environment, trigger event, etc.
- The workflow presents this token to the cloud provider (AWS STS, GCP Workload Identity Federation, Azure AD)
- The cloud provider verifies the signature against GitHub’s public keys, checks the claims against the cloud identity applied conditions, and issues short-lived credentials
In AWS, the associated cloud identity is an IAM Role which has a trust policy with a condition that typically looks something like this:
{
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:sub":
"repo:organization/internal-repo:environment:production"
}
}
}
The sub (subject) claim in the JWT is what makes this whole thing work. The condition in the cloud identity checks this string to uniquely identify which repository and context the request is coming from, and the cloud provider determines whether to allow it (or not) to assume the role. For GitHub Actions, the subject takes the form: repo:<owner>/<repository>:<qualifier>, where the qualifier can be a branch (ref:refs/heads/main), an environment (environment:production), or a pull request reference.
This is the convention of all major CI/CD platforms, and what makes the sub claim the foundation of OIDC-based cloud identities. And this is exactly where things break down.
The Concept: Reclaim Namespaces to Take Over Cloud Identities
At Astrix, we have a unique vantage point: we see thousands of Cloud environments and monitor millions of NHIs: AWS roles and access keys, Azure service principals and GCP service accounts and workload identities.
When we started parsing the configuration of these identities, we found many that are configured to trust external OIDC issuers.
By inspecting the list of unique providers we found something interesting: while most issuers (like identity providers such as Entra ID, Google Workspace, Okta and Duo) take a distinct domain in every single tenant, there were a few issuer domains that appeared identically in multiple different tenants.
When we dug deeper, we found the cloud identities designated to be used as part of CI/CD processes condition on JWTs signed by global public issuer – the same OIDC issuer provides tokens for completely different tenants.
But if the issuer is global and public, we can use it to mint JWTs for any subject under our control. This immediately begged the question: is it possible to take over the trusted subjects for those OIDC-based identities?
The answer turned out to be more interesting than we expected. The reason is namespace reuse.
Surprisingly to us, all major CI/CD platforms allow namespace reuse: for instance in GitHub, when a user or organization changes their GitHub username, that namespace becomes available again for others to use after a cooldown period.
As we showed above, GitHub Action’s sub claim is constructed entirely from identifiers fully controlled by whoever controls the namespace!
Let’s say some company owns the GitHub organization corp-payments, under which a repository payment-services hosts the payment pipeline of the company. Then an example sub claim for their associated cloud identity repo:corp-payments/payment-service:environment:production is derived purely from a path controlled by whoever owns corp-payments.
If the namespace is ever released (the company changes name, the group decommissioned, etc.), then anyone can take over the corp-payments GitHub namespace and thus its associated cloud identity by recreating the path in the sub claim condition.
This creates what we call Phantom Cloud Identities: in your cloud environment that still reference an OIDC subject whose original owner is gone. The role sits there, quietly trusting a subject that is now up for grabs.
What makes this a vulnerability class (or an incidental misconfiguration by a single provider) is that the design choice that GitHub took – operating a global OIDC issuer while allowing for namespace reuse – was also taken by every other major CI/CD we looked at.
Since there is no tenant-level isolation at the issuer. The only thing separating your CI/CD tokens from any other CI/CD tokens is the sub claim and this claim is only as permanent as the namespace it’s built on.
This is Sub:jugation.
Exploiting Sub:jugation in GitHub Actions
Let’s walk through the full attack chain on GitHub.
The Setup (Victim’s Side)
A finance team at ExampleCorp deploys their application from corp-payments/payment-service to AWS. They’ve done things the “right” way using OIDC-based credentials, and their IAM role PaymentServiceDeployer has a trust policy that only allows a GitHub Action running from that repository to assume it:
{
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:sub": "repo:corp-payments/payment-service:*"
}
}
}
The Trigger
Six months later, ExampleCorp sunsets the payment-service. The repository gets deleted alongside the GitHub user. The team moves on but no one offboards the IAM role.
The Attack
- An attacker identifies that the namespace corp-payments/payment-service is no longer registered on GitHub
- The attacker creates a new user named corp-payments, and a repository named payment-service.
- The attacker pushes a GitHub Actions workflow that requests an OIDC token and uses it to assume the target role:
jobs:
assume-role:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/PaymentServiceDeployer
aws-region: us-east-1
- GitHub’s OIDC provider issues a token with sub: repo:corp-payments/payment-service:environment:production.
- AWS receives the token, validates the signature against GitHub’s trusted public keys, checks the sub claim against the trust policy and…it matches.
- The attacker receives valid, short-lived AWS credentials for PaymentServiceDeployer and inherits all permissions it has within ExampleCorp’s AWS account.
The phantom identity has been sub:jugated.
Whitebox Data Analysis
As evident from the attack scenario, the attacker needs to achieve two crucial pieces of information to conduct a successful Sub:jugation on a GitHub actions workflow:
- A previously-active, now-deleted GitHub namespace (organization or user)
- An exact identity identifier within the organization’s Cloud that trusts a repository under that GitHub namespace
While the first piece can be trivially achieved by monitoring GitHub users or organizations using public API, the second piece is a bit trickier: the attacker doesn’t have access organizations’ Cloud environment and thus cannot easily know the identity name (typically required in order to “use” it), nor the exact condition applied on the sub claim.
However, we found that this is still possible!
Before we figured out how to do that, we first wanted to prove whether sub:jugation is really prevalent. Luckily, Astrix has the unique opportunity to see into thousands of Cloud environments and determine exactly how common Sub:jugation really is.
We took all AWS and Azure identities that trust GitHub Action’s provider https://token.actions.githubusercontent.com, parsed the sub condition in their trust policy and checked if the trusted namespace is still taken in GitHub.
The results were surprising:
- In AWS, 14% of discovered namespaces were not registered and available to be taken.
- In Azure, the percentage jumps to 24%!
- On average a single deleted namespace had more than 12 different NHIs trusting one of its repositories
- Surprisingly, how long an OIDC-based Cloud identity existed has no clear effect on the chances for it to be a Phantom Identity, with NHIs having around 8% chance to be deleted across different creation times
These results clearly show that Sub:jugation is more common than expected. Organizations seem to not offboard associated cloud identities when sunsetting projects in GitHub.
Threat Model: Recon by External Attacker
While we utilized our unique position to conduct this analysis, an attacker doesn’t have such privilege. So let’s go back to the previous question: how can a threat actor without access to internal data find which namespaces to target and get an exact identity name to take over?
We found that this is possible in several ways, the most prolific one was utilizing GitHub’s Code Search, an extensive search functionality over the vast code repositories that GitHub hosts.
Because GitHub Actions workflows are themselves code, they are searchable and, by constructing clever queries, one can find Cloud identities that trust a GitHub namespace:
- Use path:.github/workflows to only conduct search over GitHub Action workflows
- Search for the id-token: write permission which is required to get a signed JWT from GitHub’s global issuer
- For cloud-associated sub-actions or yaml directives:
- For AWS: aws-actions/configure-aws-credentials, and role-to-assume.
- For Azure: azure/login, and client-id
- For GCP: google-github-actions/auth, and workload_identity_provider
Searching workflows this way will provide namespaces and repositories that rely on OIDC-based Cloud Identities. However, it won’t be necessarily possible to retrieve the identity’s identifier, as the best practice for workflows is to populate this field using environment variables that are set by the repository owner and are not publicly available.
Unfortunately, people don’t always follow best practices. To show how often, we conducted this reconnaissance technique ourselves over the past six months, and found ~28,000 GitHub workflows that request OIDC tokens, out of which ~10,000 were verified to use OIDC for access into one of the major cloud providers.
The most important data point, however, is that over 13% of those workflows had cleartext identifiers for the cloud identities they used!
The breakdown per platform is as follows:
- A total of 1789 workflows using GCP Workload Identity Federation. Out of which 514 had a cleartext Workload Identity Provider and Service Account
- A total of 4794 workflows using Azure Federated Identities. Out of which 45 had a cleartext Application Registration details. It seems that the vast majority of Azure workflows developers use variables
- A total of 3710 workflows using AWS Roles. Out of which 814 had a cleartext Role ARN
That’s a lot of Cloud identities to take over!
While running this reconnaissance, we funneled the resulting potential vulnerable namespaces into a separate process that periodically checks if the namespace is available to be reclaimed.
The results were mindblowing. We found that there are about 300 new OIDC-based workflows created each day on GitHub (that’s about 1 million a year!). The interesting data is that on average, almost 2 namespaces are deleted every day (~60 a month)..
Combining this with the 13.38% of workflows which contain a cleartext cloud identity identifier, we find that on average, every month 8 phantom cloud identities are up for grabs, completely based on publicly available data.
Consequences of the Findings
- There are eight no-requirement entry points to real cloud environments every month.
This means initial access to gain a foothold inside organizations can be accumulated passively over time - It’s not just individuals lacking proper off-boarding: some of the deleted namespaces we found belonged to large organizations who simply
- Just one issuer and one recon technique: we searched for cloud identities vulnerable to sub:jugation in GitHub Actions, utilizing GitHub Code Search. There are more techniques to discover more vulnerable identities, such as using the Intent Archive to look for already-deleted namespaces
Sub:jugation in the Wilderness of CI/CD Platforms
At that point, we understood that sub:jugation is more impactful than we previously thought, even when the threat model is of an attacker without sensitive access.
Expanding on the last point of sub:jugation’s consequences listed above, we only even looked at a single CI/CD platform! There are a bit more than that, all complying with the modern way of authenticating to cloud environment using OIDC
So, we went out searching for sub:jugation in other providers, and found Gitlab CI and HCP Terraform Runs suffer from the same issue! Below is a summary of our findings:
Disclosure
We responsibly disclosed our findings to GitHub, Gitlab and Terraform. All reports were received and triaged. Following are the details of the timeline per provider.
GitHub
– 2/16/2025 — Reported sub:jugation against GitHub Actions to GitHub
– 3/6/2025 — Submission validated and triaged
– 2/12/2026 — Bounty paid, working on a fix
– 5/28/2026 — GitHub rolled out a fix: a random identifier added to the sub claim for the username and repository
– 6/4/2026 — Public blog expected to go live
GitLab
– 3/31/2026 — Reported sub:jugation against GitHub CI to GitLab Security
– 4/6/2026 — Ticket closed as informational by HackerOne triage service, asserting the attack is purely theoretical
– 5/18/2026 — Ticket reopened by Gitlab team and assigned to engineering team
– 6/1/2026 — Mitigating fix released by GitLab, followed by a comprehensive one, in a similar manner to the other vendors
Terraform
– 5/10/2026 — Reported sub:jugation against HCP Terraform Runs to Terraform Security
– 5/11/2026 — Report received and awaiting fix by engineering team
– 6/1/2026 — Terraform added an update to language and warnings when changing an organization name
– TBD — A permanent solution changing how OIDC subjects are handled is expected to be implemented
What Should You Do Tomorrow?
- Find all cloud identities trusting global issuers
Look for global issuers’ domains (token.actions.githubusercontent.com, gitlab.com, app.terraform.io) across AWS / GCP / Azure - For each policy, verify the namespace still exists and is still under your control
Take the namespace from the sub claim condition and test if it is still active and controlled by you. Typically a simple API request - Fix inactive namespaces
Take over the namespace, or off-boarding the referencing cloud identity. On GitHub no fix is required once their patch lands.
Summary and How Can Astrix Help
The sub:jugation vulnerability class reveals a quiet but significant risk at the intersection of CI/CD identity and cloud IAM: the subjects of your OIDC trust policies are only as permanent as the repository namespaces they’re built on.
The attack requires no expertise or complex attack scenarios. It simply exploits the gap between the reclaimable namespace and fully-controll paths used to construct OIDC subjects and the lack of off-boarding process of cloud NHIs.
These Phantom Cloud Identities sit silently in cloud environments today. They don’t show up in the usual audit audits or access reviews, mostly forgotten by the teams that originally configured them.
Astrix’s Non-Human Identity (NHI) security platform continuously maps the connections between your CI/CD pipelines, non-human identities, and the cloud resources they access. This means Astrix can surface improperly offboarded NHI before the attackers will put their hands on them.
Beyond detection, Astrix helps organizations enforce least-privilege across their non-human identity inventory like right-sizing the permissions on deployment roles and flagging over-privileged cloud access granted to CI pipelines.