AWS access-key compromise followed by IAM privilege escalation
Public-safe case study Customer names, account IDs, principals, access-key identifiers, IP addresses, resource names, evidence locations, and case-specific identifiers have been removed or replaced. Quantitative findings and defensive lessons are retained for educational use.
Executive assessment
A long-lived access key assigned to a CI service user was used from a first-seen autonomous system to enumerate IAM, assume a deployment role, attach an inline administrator policy, and create a second access key. CloudTrail establishes a confirmed privilege-escalation chain. The original key was disabled 12 minutes 18 seconds after the first unauthorized API call; derived sessions were revoked and the persistence key deleted.
95% autonomous investigation. 100% human authority.
TandemTrace AI agents completed 38 of 40 recorded investigation actions autonomously. The cloud security lead retained final verdict approval and containment authorization.
Agents reconstructed the identity chain. A human controlled cloud-impact decisions.
Investigation dataset
- Alert
- GuardDuty · anomalous IAM API activity
- First observed
- 2026-07-30 03:17:22 UTC
- Principal
- svc-ci-release · long-lived IAM key
- Account
- Production workload account
- Origin
- First-seen network · replacement IP
- CloudTrail
- 9,842 management events · 24 hours
- GuardDuty
- 4 related findings
- IAM
- 23 users · 61 roles · policy history
- Organizations
- 3 accounts · SCP evaluation
- Workload
- CI logs, Secrets Manager, S3 data events
| Artifact | Sanitized value | Baseline | Assessment |
|---|---|---|---|
| Access key | AKIA…7Q2M | CI runner only | Used outside workload network |
| Source | 192.0.2[.]81 | Never observed | TEST-NET replacement |
| User agent | aws-cli/2.17 Python/3.11 | CI uses SDK/Go | Baseline mismatch |
| Policy | EmergencySupport | No approved change | Administrator wildcard |
Evidence that changed the verdict
Impossible workload origin
The access key had only appeared from two fixed CI egress addresses during its 94-day history. The new source and CLI user agent had no baseline match.
Privilege expansion
The assumed role added an inline policy allowing all actions on all resources. No deployment workflow or approved change required IAM mutation.
Persistence created
A second key was created for the service user and immediately validated from the same external source.
Defense checks
The actor queried CloudTrail trail status and account authorization details before attempting Secrets Manager access.
Correlated timeline
GetCallerIdentity succeeds from a first-seen source and user agent.
ListUsers, ListRoles, and GetAccountAuthorizationDetails enumerate privilege paths.
The compromised principal assumes the production release role.
An inline wildcard policy is attached to the role.
A second access key is created and validated.
Both keys disabled, sessions revoked, and the malicious policy removed.
Competing hypotheses
| Hypothesis | Evidence for | Evidence against | Outcome |
|---|---|---|---|
| Approved CI deployment | Known service identity | Wrong source, user agent, commands, and change window | Rejected |
| Administrator troubleshooting | Role name permits deployment | No SSO session, ticket, owner confirmation, or IAM-change precedent | Rejected |
| Stolen long-lived key | Baseline break, discovery, escalation, persistence | Exposure location not conclusively identified | Confirmed use; leak path open |
Scope and evidence boundary
Cross-account prevalence
3 accounts · 24h| Question | Result | Meaning |
|---|---|---|
| Other use of either key? | 0 additional sources | Observed activity confined to one sequence |
| Other roles assumed? | 0 | No confirmed cross-account role chain |
| Secrets retrieved? | 3 denied, 0 successful | Secret access not observed |
| Data-plane access? | 0 matching S3 data events | Exfiltration not observed in enabled logs |
Evidence boundary S3 data events were enabled for protected buckets, but not every bucket in the organization. The investigation cannot claim that no unlogged data-plane access occurred.
Response actions
Completed after human authorization.
Preserve CloudTrail and IAM evidence before remediation.
Treat reachable secrets as exposed until validated.
Use short-lived role credentials and restrict assumption by source and context.
Technical evidence
| ID | Source | Event UTC | Principal | Verdict contribution |
|---|---|---|---|---|
| A-01 | CloudTrail | 03:17:22 | svc-ci-release | Baseline-breaking key use |
| A-02 | CloudTrail | 03:19:06 | assumed-role/release | Role chain established |
| A-03 | CloudTrail | 03:20:14 | assumed-role/release | Privilege escalation confirmed |
| A-04 | CloudTrail | 03:21:03 | svc-ci-release | Persistence confirmed |
| A-05 | GuardDuty | 03:22:11 | access key | Anomalous behavior corroborated |
MITRE ATT&CK mapping
| Technique | Observed behavior |
|---|---|
| T1078.004 · Cloud Accounts | Compromised access key authenticated to AWS APIs. |
| T1087.004 · Cloud Account Discovery | IAM users and roles enumerated. |
| T1098.001 · Additional Cloud Credentials | A second access key established persistence. |
| T1548 · Abuse Elevation Control Mechanism | Inline wildcard policy expanded privileges. |
| T1526 · Cloud Service Discovery | Account and service configuration queried. |