infrastructure-as-code
format
cloud
region
# ================================================================
# Attack path: GitHub Actions OIDC role takeover
# Difficulty: medium · Cloud: aws · Est. time: 20 min
#
# Starting position: Any GitHub user; you can create a workflow in a repo you control.
# Objective: Assume the target AWS role from an arbitrary workflow you own.
#
# Playbook:
# 1. Discovers the target's role ARN — often committed to a public `.github/workflows/*.yml` or leaked in build logs.
# 2. Creates a workflow in their own repo that calls `aws-actions/configure-aws-credentials` with the target role-arn. The role's trust policy has no `sub` condition.
# exploits: IAM-040
# 3. Workflow assumes the role and runs `aws sts get-caller-identity` → AdministratorAccess. Pivots to any resource.
# exploits: IAM-040, IAM-041
#
# Cleanup: terraform destroy -auto-approve (or: aws cloudformation delete-stack)
# ================================================================
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
random = { source = "hashicorp/random", version = "~> 3.6" }
}
}
provider "aws" {
region = "us-east-1"
}
resource "random_id" "suffix" {
byte_length = 4
}
# Weak OIDC trust
# vulnerabilities: IAM-040, IAM-041
resource "aws_iam_openid_connect_provider" "id_oidc_trust" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
resource "aws_iam_role" "id_oidc_trust" {
name = "vbuild-id-oidc-trust"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Federated = aws_iam_openid_connect_provider.id_oidc_trust.arn }
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
# IAM-040: no sub-claim restriction — ANY GitHub workflow can assume.
# Real fix: "token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:ref:refs/heads/main"
}
}
}]
})
}
resource "aws_iam_role_policy_attachment" "id_oidc_trust_admin" {
role = aws_iam_role.id_oidc_trust.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
intentionally vulnerable. Apply only in an isolated sub-account / project, time-boxed and tagged. Never deploy on top of production.