
TL;DR: awslabs.cloudtrail-mcp-server exposes five CloudTrail tools to Claude Code. Point it at a read-only IAM profile. Run five hunt prompts covering the MITRE T1078–T1562 credential-access cluster. Claude flags anomalies; you triage them.
Eat a slice of pizza while Claude Code churns through 90 days of CloudTrail history and tells you what looks wrong.
The Problem
DevOps environments are a wide attack surface. CI/CD pipelines, OIDC federation, long-lived access keys, and container registries all produce AWS credentials. When one leaks, attackers move fast: leaked keys are probed within minutes of appearing in a public repo.
Manual CloudTrail review does not keep pace. A busy AWS account generates thousands of API events per day - cross-account calls, assumed roles, and service-linked roles - and the signal-to-noise ratio stays low throughout.
These five hunt patterns target the actions that matter:
MITRE Technique | What to Hunt |
|---|---|
T1078.004 - Valid Cloud Accounts | GetCallerIdentity from anomalous IPs or ASNs |
T1087.004 - Account Discovery | IAM enumeration: ListUsers, ListRoles, GetAccountSummary |
T1098 - Account Manipulation | Privilege escalation: AttachUserPolicy, CreateAccessKey |
T1550.001 - Application Access Token | OIDC / web identity tokens used outside CI/CD ASNs |
T1562.008 - Disable Cloud Logging | StopLogging, DeleteTrail, PutEventSelectors |
Prerequisites
AWS account with CloudTrail enabled (management events, all regions)
IAM profile with these six read-only actions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"cloudtrail:ListEventDataStores",
"cloudtrail:GetEventDataStore",
"cloudtrail:StartQuery",
"cloudtrail:DescribeQuery",
"cloudtrail:GetQueryResults"
],
"Resource": "*"
}
]
}Use a read-only IAM profile scoped to these six actions for threat hunting. Analyst activity must never touch production credentials or write-capable policies.
Claude Code installed:
npm install -g @anthropic/claude-codeuvxavailable:pip install uvCloudTrail Lake event data store (optional - needed for Hunts 3–5 which use SQL)
Step 1: Install the MCP Server
Command: Send below command to terminal
uvx awslabs.cloudtrail-mcp-server --helpThis confirms uvx can pull and run the package. No separate install step is needed - uvx handles the Python environment on each run.
Step 2: Configure Claude Code
Add this to .claude/settings.json in your project directory:
{
"mcpServers": {
"cloudtrail": {
"command": "uvx",
"args": ["awslabs.cloudtrail-mcp-server"],
"env": {
"AWS_PROFILE": "threat-hunt-readonly",
"FASTMCP_LOG_LEVEL": "ERROR"
},
"transportType": "stdio"
}
}
}
Replace threat-hunt-readonly with your read-only profile name. FASTMCP_LOG_LEVEL=ERROR suppresses server noise in the Claude Code terminal.
Step 3: Verify the Connection
Command: Send below command to terminal
claudeOnce inside Claude Code, run:
Prompt: Send below prompt to Claude Code
/mcpStep 4: Hunt 1 - Credential Validation (T1078.004)
Every stolen-key attack starts with sts:GetCallerIdentity: the attacker confirms the key is valid and maps the account before doing anything else.
Prompt: Send below prompt to Claude Code
You are a cloud threat hunter. Use the CloudTrail MCP server to search for GetCallerIdentity
calls in the past 30 days.
For each result, check:
1. Is the source IP in an expected range for this account (CI/CD systems, developer offices)?
2. Does the user agent match expected tooling (aws-cli, boto3, Terraform)?
3. Is the call timing outside business hours?
Flag any call where source IP is unexpected OR user agent is unusual.
Output a table: timestamp | principal | source IP | user agent | flag reason
Do not modify any file outside hunt-results/.A clean account returns only known IPs and tool names. A call from 45.129.14.x (a common cloud-scanning ASN) with user agent python-requests/2.28.0 is worth escalating.
Step 5: Hunt 2 - IAM Enumeration (T1087.004)
Attackers map permissions after validating credentials. ListUsers, ListRoles, and GetAccountSummary together in a short window from a single principal is the pattern.
Prompt: Send below prompt to Claude Code
You are a cloud threat hunter. Use the CloudTrail MCP server to search for IAM enumeration
events in the past 7 days.
Target events:
- iam:ListUsers
- iam:ListRoles
- iam:GetAccountSummary
- iam:ListAttachedUserPolicies
- iam:ListAttachedRolePolicies
Flag any principal that called 3+ of these actions within a 10-minute window.
Output: principal | events called | window start | window end | source IP
Do not modify any file outside hunt-results/.A developer running aws iam list-users once is normal. Five enumeration calls in 90 seconds from an EC2 instance role is not.
Step 6: Hunt 3 - CI/CD Token Theft (T1550.001)
OIDC tokens issued to GitHub Actions or GitLab CI are scoped to specific ASNs. When the same assumed-role session appears from an ASN outside CI/CD infrastructure, the token was likely exfiltrated.
This hunt requires CloudTrail Lake (Trino SQL, up to 10 years of retention).
Prompt: Send below prompt to Claude Code
You are a cloud threat hunter. Use the CloudTrail Lake MCP server to find AssumeRoleWithWebIdentity
calls where the same role was assumed from two different network locations in the same day.
Query logic:
- Find all AssumeRoleWithWebIdentity events in the past 14 days
- Group by roleArn and date
- Flag roleArns that appear with more than one distinct source IP block (/24)
- Separate CI/CD ASNs (GitHub Actions: 140.82.0.0/16, GitLab: 34.74.0.0/16) from all others
Output: roleArn | ci_cd_ip | external_ip | date | verdict
Do not modify any file outside hunt-results/.Finding the same role session from 140.82.112.x (GitHub) AND 185.220.101.x (Tor exit node) on the same day is high severity.
Step 7: Hunt 4 - Privilege Escalation (T1098)
Post-compromise, attackers attach admin policies or create new access keys to persist access.
Prompt: Send below prompt to Claude Code
You are a cloud threat hunter. Use the CloudTrail MCP server to find privilege escalation
attempts in the past 14 days.
Target events:
- iam:AttachUserPolicy (especially AdministratorAccess or PowerUserAccess)
- iam:AttachRolePolicy
- iam:CreateAccessKey
- iam:PutUserPolicy (inline policies)
- iam:UpdateAssumeRolePolicy
For each hit:
1. What principal made the call?
2. What was the target principal?
3. Was this principal also seen in IAM enumeration events in the prior 24 hours?
Output: timestamp | actor | target | action | policy attached | prior enumeration?
Do not modify any file outside hunt-results/.An iam:AttachUserPolicy for AdministratorAccess by a principal that called ListRoles 20 minutes earlier is a confirmed attack sequence.
Step 8: Hunt 5 - Log Tampering (T1562.008)
Attackers who want to hide their activity disable logging. StopLogging, DeleteTrail, and PutEventSelectors with reduced event scope are the three actions to watch.
Prompt: Send below prompt to Claude Code
You are a cloud threat hunter. Use the CloudTrail MCP server to search for any CloudTrail
configuration changes in the past 30 days.
Target events:
- cloudtrail:StopLogging
- cloudtrail:DeleteTrail
- cloudtrail:PutEventSelectors (check if management events were narrowed or excluded)
- cloudtrail:UpdateTrail
For each hit:
1. What was changed?
2. What was the before/after configuration?
3. Was logging restored within 5 minutes (possible authorized change)?
Output: timestamp | principal | action | trail ARN | change summary | logging restored?
Do not modify any file outside hunt-results/.
Any StopLogging not followed by StartLogging within 5 minutes from an ops principal is an incident, not a mistake.
Step 9: Run All Five as an Autonomous Loop
The /goal command runs Claude Code in a loop until a verifiable condition is met. Use it to run all five hunts unattended and get a single verdict file. For a full breakdown of how /goal works in security workflows, see Using /goal in Claude Code for Autonomous Security Engineering Workflows.

Prompt: Send below prompt to Claude Code
/goal Run all five credential-access hunt patterns (GetCallerIdentity anomalies, IAM enumeration,
OIDC token abuse, privilege escalation, log tampering) against the past 30 days of CloudTrail data.
Success condition: All five hunts complete with findings written to hunt-results/.
If any hunt returns a HIGH or CRITICAL finding, write ESCALATE.md listing the finding,
affected principal, and recommended action, then stop.
If all five complete with zero findings, write CLEAN.md with a timestamp and summary.
Do not modify any file outside hunt-results/.Interrupt at any time with Ctrl+C. Run headless (no interactive terminal) with:
Command: Send below command to terminal
claude --print "/goal Run all five credential-access hunt patterns..."Step 10: Triage the Findings
Claude Code produces a structured findings table. Each row needs a human decision.
Triage process:
Confirm the principal exists. Run
aws iam get-useroraws sts get-caller-identityagainst the flagged ARN.Check the IP. Look up the ASN. Known CI/CD ranges, corporate egress, or VPN are usually safe. Cloud-hosting ASNs or anonymizing infrastructure are not.
Check the time. Calls at 03:00 UTC from a developer principal warrant explanation.
Look for sequences. GetCallerIdentity → ListRoles → AttachUserPolicy in the same hour from the same IP is a confirmed attack chain.
If the finding is valid:
Disable the access key immediately:
aws iam update-access-key --access-key-id <KEY_ID> --status InactiveDo not delete it yet; you need the key ID for forensics.
Attach an explicit deny policy to the principal as a containment measure.
Open an incident. Preserve the CloudTrail event JSON.
Running This on a Schedule
Add this to your project's CLAUDE.md so each new Claude Code session inherits the hunting context:
# Threat Hunt Context
AWS account: production
Hunt scope: credential access (T1078, T1087, T1098, T1550, T1562)
Output directory: hunt-results/
IAM profile: threat-hunt-readonly
Do not modify files outside hunt-results/.Then schedule via cron or CI/CD:
Command: Send below command to terminal
# Run every Monday at 06:00 UTC
0 6 * * 1 cd /path/to/hunt && claude --print "/goal Run weekly credential-access hunt. Write ESCALATE.md or CLEAN.md in hunt-results/." >> hunt-results/weekly-$(date +%Y%m%d).log 2>&1Further Reading
Using /goal in Claude Code for Autonomous Security Engineering Workflows - how /goal loops work, exit conditions, and headless execution patterns
AWS CloudTrail MCP Server - source and full tool reference
MITRE ATT&CK for Cloud - Credential Access - technique catalog
CloudTrail Lake SQL reference - Trino dialect constraints
AWS IAM Access Analyzer - complements CloudTrail hunts with static analysis
CISA Advisory on Cloud Credential Theft - real-world TTPs this hunt targets
Subscribe to SecEngAI for Applied AI for Security Engineering
