Skip to content
Free tool · no signup

IAM Trust Policy Auditor

Paste an AWS IAM role trust policy (the AssumeRolePolicyDocument) and get severity-ranked findings for cross-account and federation risk: wildcard principals that let anyone assume the role, account-root trust missing an ExternalId (the classic confused-deputy gap), wildcard principal ARNs, and unconditioned SAML/OIDC federation. Each finding says who can assume the role, why that is dangerous, and how to fix it. Everything runs in your browser; nothing is uploaded.

Role trust policy JSON (AssumeRolePolicyDocument)
·

Runs entirely in your browser — nothing is uploaded. Your trust policy is parsed and audited locally with JavaScript; it never leaves this page, so it is safe to paste a production AssumeRolePolicyDocument without sending it to any server.

TL;DR

What this tool is

  • A free, in-browser auditor for AWS IAM role trust policies (the AssumeRolePolicyDocument): paste the JSON and it finds who can assume the role and why that is risky.
  • Flags wildcard principals — Principal "*" or Principal {"AWS":"*"} with sts:AssumeRole — as critical, because any account (or anyone) can then assume the role and inherit its permissions.
  • Flags cross-account account-root trust with no sts:ExternalId as the classic confused-deputy risk for third-party vendors, plus wildcard principal ARNs and unconditioned SAML/OIDC federation.
  • Every finding gives the severity, the offending statement, a plain-English explanation of who can assume the role, and a concrete fix (add an ExternalId, pin account IDs, add sub/aud conditions).
  • Runs 100% client-side with zero network calls — your trust policy is parsed in the browser and never uploaded, so it is safe to paste a production policy.

Trust policy vs permission policy

Every IAM role carries two very different kinds of policy. Its permission policies say what the role can do once someone is operating as it. Its single trust policy — stored as the role's AssumeRolePolicyDocument — says who is allowed to become the role in the first place. The trust policy is a resource-based policy: its Principal element names the trusted identities, the Action is almost always sts:AssumeRole (or the SAML / web-identity variants), and the optional Condition narrows when the trust applies. Mis-scope the Principal or omit a Condition and you can hand a powerful role to an entire account, an entire identity provider, or — in the worst case — the whole internet.

What this auditor flags

  • Public trust (critical). Principal "*" or {"AWS":"*"} with sts:AssumeRole — any account, or anyone, can assume the role.
  • Account-root trust with no ExternalId (high). A whole-account root principal (arn:aws:iam::ACCT:root) and no sts:ExternalId condition — the confused-deputy setup for third-party vendors.
  • Wildcard principal ARN (high). A * inside a principal ARN (e.g. arn:aws:iam::*:root) matches far more identities than intended.
  • Open SAML / OIDC federation (high). A Federated principal with no :sub / :aud (or saml:aud) condition trusts everyone the identity provider can mint a token for.
  • Service-principal confused-deputy gap & unconditioned cross-account trust (medium). A service principal with no aws:SourceArn/aws:SourceAccount, or a specific cross-account principal with no Condition at all.

The confused-deputy mechanic

The highest-value finding is the account-root trust without an ExternalId. When a SaaS vendor manages resources in your account, it asks you to create a role trusting the vendor's AWS account. If that trust names only the account, the vendor becomes a confused deputy: another of its customers can induce the vendor to call sts:AssumeRole against your role, because nothing ties the call to you. AWS's purpose-built fix is sts:ExternalId: a per-customer secret the vendor must present on every AssumeRole call, enforced by a StringEquals condition. Different customer, different ID — the deputy can no longer be confused. For trust inside your own organization, aws:PrincipalOrgID is an acceptable alternative guard; for service principals, use aws:SourceArn / aws:SourceAccount.

Scope note: this is a heuristic read of the trust-policy text only. It cannot see the role's own account id, its permission policies, service control policies or runtime session context, so it can neither prove a trust path is exploitable nor prove one is safe. Treat it as a fast first pass, then confirm serious findings with AWS IAM Access Analyzer external-access findings. Prefer naming specific role/user ARNs over an account root, and always pair a broad trust with a Condition.

Trust Policy Auditor — animated demo
A quick look at Trust Policy Auditor — it runs entirely in your browser.

Frequently asked questions

What is an IAM role trust policy?

A trust policy — stored on a role as its AssumeRolePolicyDocument — is the resource-based policy that answers one question: who is allowed to assume this role? It is separate from the role’s permission policies (which say what the role can do once assumed). A trust policy statement has a Principal (who is trusted), an Action (almost always sts:AssumeRole, sts:AssumeRoleWithSAML or sts:AssumeRoleWithWebIdentity) and an optional Condition. Getting the Principal or Condition wrong is how roles get handed to the wrong people, so the trust policy is one of the highest-leverage things to audit in an AWS account.

What is the confused-deputy problem and how does ExternalId fix it?

The confused deputy is a third party (the "deputy") that is tricked into misusing authority it legitimately holds. In AWS, a SaaS vendor often asks you to create a role trusting the vendor’s AWS account so it can manage resources for you. If the trust policy only names the vendor’s account, another of the vendor’s customers could ask the vendor to assume a role in YOUR account — the vendor is the confused deputy. The fix AWS designed for this is sts:ExternalId: the vendor gives you a unique ID, you put it in a Condition (StringEquals on sts:ExternalId), and the vendor must pass that exact ID when assuming the role. Because each customer’s ID is different, the vendor can no longer be tricked into assuming your role on someone else’s behalf.

Why is Principal "*" (or {"AWS":"*"}) in a trust policy so dangerous?

A trust policy Principal of "*" means every principal is trusted to assume the role; {"AWS":"*"} means every AWS account in the world is trusted. Combined with sts:AssumeRole, that is a public handover of the role: any attacker with any AWS account can call AssumeRole and receive temporary credentials carrying all of the role’s permissions. It is one of the few genuinely critical misconfigurations because it requires no other flaw to exploit — the trust is open by design. A wildcard principal is only ever acceptable when paired with a strongly restrictive Condition, and even then naming the principals explicitly is far safer.

How should I scope a SAML or OIDC (web-identity) federation trust?

Federated trust (AssumeRoleWithSAML or AssumeRoleWithWebIdentity) trusts an identity provider, not a specific user — so without a Condition it trusts everyone the provider can issue a token for. For SAML, add a StringEquals condition on saml:aud (the audience, e.g. https://signin.aws.amazon.com/saml). For OIDC/web identity, pin both the audience and the subject: the provider’s :aud (often sts.amazonaws.com) and its :sub. For GitHub Actions, for example, the :sub should match the exact repository and ref (repo:org/name:ref:refs/heads/main), otherwise any repository under that OIDC provider — including forks or unrelated repos — could assume the role.

Does this tool send my trust policy anywhere?

No. The entire audit runs client-side in your browser with JavaScript — the policy JSON is parsed and analysed locally, there are zero network calls, and nothing is uploaded, logged or stored on a server. That is why it is safe to paste a real production AssumeRolePolicyDocument. The analysis is a heuristic read of the trust-policy text only: it cannot see the role’s own account id, its permission policies, service control policies or runtime session context, so treat it as a fast first pass and confirm serious findings with AWS IAM Access Analyzer external-access findings.

🎉 New here? Use code WELCOME10 for 10% off any plan at checkout
IAM Trust Policy Auditor — Audit AssumeRole Policies for Cross-Account Risk · PlayCISO