# AWS Account ID and IAM Discovery

> Techniques for enumerating AWS Account IDs and IAM principals using unauthenticated and authenticated methods to map cloud identity attack surface.

- **URL:** https://hackindex.io/platforms/aws/reconnaissance/aws-account-id-and-iam-discovery
- **Path:** AWS > Reconnaissance
- **Up:** [Reconnaissance](https://hackindex.io/platforms/aws/reconnaissance.md)
- **Published:** 2026-05-24
- **Updated:** 2026-05-24

Before touching any AWS API with credentials, collect what you can passively. Account IDs, IAM role names, and ARN patterns narrow your attack surface and inform later privilege escalation attempts.

## Account ID from Public S3 Buckets

Public S3 bucket ACL responses leak the account ID of the bucket owner. If you found a public bucket during S3 recon:

```bash
aws s3api get-bucket-acl --bucket $BUCKET --no-sign-request
# {
#     "Owner": {
#         "DisplayName": "company-aws",
#         "ID": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be"
#     }
# }
```

The `ID` is a canonical user ID, not the account ID directly: but it can be correlated. For the numeric account ID, check SNS topic ARNs or other public resources.

## Account ID from Public AMIs

Organizations frequently publish AMIs with their account ID embedded in the ARN. Search for AMIs by company name or known product:

```bash
aws ec2 describe-images --filters "Name=name,Values=*$COMPANY*" --no-sign-request --region us-east-1
# {
#     "ImageId": "ami-0abc123",
#     "OwnerId": "123456789012",
#     "Name": "company-app-server-2024"
# }
```

`OwnerId` is the 12-digit AWS account ID.

## Account ID from Public ECR Repositories

Public ECR image URIs contain the account ID:

```
123456789012.dkr.ecr.us-east-1.amazonaws.com/repo-name
```

Search Docker Hub, GitHub Actions logs, CI/CD configs, and public documentation for ECR image references.

## Account ID from Exposed ARNs

ARNs appear in:

- GitHub Actions workflow YAML (`role-to-assume: arn:aws:iam::123456789012:role/...`)
- CloudFormation templates in public repos
- Terraform state files accidentally committed
- Job listings and blog posts referencing AWS infrastructure
- Error messages returned by web applications running on AWS

Search GitHub:

```
"arn:aws:iam" "$COMPANY" filename:.yml
"arn:aws:iam" "$DOMAIN"
"role-to-assume" "$COMPANY"
```

## IAM Role Names from GitHub Actions

GitHub Actions workflows that assume AWS roles via OIDC expose role ARNs directly in the repo:

```bash
grep -r "role-to-assume" .github/workflows/
# - uses: aws-actions/configure-aws-credentials@v4
#   with:
#     role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
#     aws-region: us-east-1
```

This gives you the account ID and an exact role name. The role may be assumable if the trust policy is overly permissive. See [OIDC Federation Abuse](https://hackindex.io/platforms/aws/exploitation/oidc-federation-abuse) for follow-up.

## Error-Based Account ID Leak

The `sts:GetAccessKeyInfo` API returns the account ID for any access key ID: no secret needed, and access keys are not secret identifiers:

```bash
aws sts get-access-key-info --access-key-id $AWS_ACCESS_KEY_ID
# {
#     "Account": "123456789012"
# }
```

If you found an access key ID (but not the secret) in source code or logs, this confirms which account it belongs to.

## Metadata from Web Applications

Applications hosted on EC2 that return verbose AWS error messages often include account IDs and ARNs in stack traces. Trigger errors on:

- Missing parameters
- Invalid input to endpoints that call AWS APIs
- 500 errors that expose IAM permission denied messages

A `AccessDeniedException` response typically contains the full ARN of the calling principal:

```
User: arn:aws:sts::123456789012:assumed-role/WebAppRole/i-0abc123 is not authorized to perform: s3:GetObject
```

This leaks: account ID, role name, and EC2 instance ID.
