A second provider, a second trust policy, and a subject claim pattern that was broader than intended.
{
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub":
"repo:turkerdev/blog:*"
}
}
}
// which permits: any branch, any pull request, any
// environment. including a pull request from a fork,
// if the workflow is misconfigured elsewhere.
// what it should be:
// "repo:turkerdev/blog:environment:production"
The wildcard is the default in every example and it is the whole security boundary — a token exchange restricted to a repository is barely better than a stored credential, because anybody who can push a branch can assume the role. Scoping to an environment that requires a reviewer is what makes the OIDC arrangement actually stronger than the key it replaced.