The Role Any Repo Can Wear: An Unpinned OIDC Trust Policy

Cloud Security Level 4/4 ~7 min October 18, 2026

The challenge

Northwind lets GitHub Actions deploy to AWS without long-lived keys: a workflow presents a short-lived GitHub OIDC token and assumes a role. Two roles trust that provider. One is for deploying the marketing site, one is full admin on the production account. Both confirm the token really is a GitHub Actions token. Only one of them also confirms which repository the token came from. Read the two trust policies and name the role that any workflow on all of github.com can assume.

What you'll learn

  • Explain what the aud and sub claims of a GitHub OIDC token mean
  • Recognise that aud is a shared constant and proves nothing about the repo
  • Identify a trust policy that omits the sub condition as critically open
  • Describe the risk of StringLike wildcards on sub and ref
  • State that trust must tighten as the role's privilege grows

Skills tested

Cloud IAM analysisReading trust policiesOIDC claim reasoning

Prerequisites

  • What an IAM role and trust policy are
  • The idea of OIDC federation for CI

How it works

Keyless CI works by a workflow presenting a short-lived OIDC token and assuming an AWS role. The role's trust policy decides who may do that, so it is the whole boundary.

A GitHub token's aud claim is the same value for every GitHub Actions run everywhere; checking it only proves the caller is some GitHub workflow. The sub claim is what names the repository and ref. A trust policy that checks aud but not sub will accept a token minted by a workflow in any repository on github.com, including one the attacker owns.

So the role must pin sub to the exact repos and refs allowed, and treat wildcards carefully: repo:org/* admits any repo in the org, and a loose ref admits any branch or a pull request.

Common mistakes

  • Answering northwind-site-deploy. Its policy pins sub to one repo and branch, so it is the safe one.
  • Thinking the aud check helps. Every GitHub token carries the same aud; it is not a scoping control.
  • Assuming an attacker cannot get a valid token. Anyone can run Actions in their own repo and receive a genuine GitHub OIDC token.
  • Reading privilege as the flaw. Admin rights make it worse, but the bug is the missing sub condition.

How to defend against it

Pin the subject, and keep privilege proportional to scoping.

  • Always add a sub condition listing the exact repo:org/name:ref:... values allowed. Never rely on aud alone.
  • Prefer StringEquals on full subjects. If you must use StringLike, avoid repo:org/* and loose refs; scope to named repos and branches.
  • Separate low and high privilege: a deploy role for one site should never share the openness of an admin role, and admin roles need the tightest possible trust.
  • Audit every web-identity role for a missing or wildcard sub.

Full solution

Pro and Max members unlock the complete step-by-step walkthrough.

Go Pro

Community stats

141 completions
82% success rate
Malekith First blood

Related Daily Hacks

34,000+ Hackers Real labs Free
Start Hacking Free or solve today's hack, no account needed