Amazon GuardDuty just paged you: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration on a Fargate task role named coding-agent-tool-prod. You revoked the key. Good. Now security asks: which tenants’ artifacts did the attacker touch, which Bedrock models were invoked, and is the same principal still hopping via AssumeRole? Raw CloudTrail answers that in six hours of Athena. Amazon Detective answers it in a graph — entity profiles, finding groups, and behavioral baselines built automatically from your GuardDuty + CloudTrail + VPC Flow telemetry. Pair with CloudTrail Lake for custom SQL and Macie if the exfil path was an artifact bucket.
⚡ TL;DR: Enable Detective in every agent account (Org delegated admin). Open GuardDuty findings from Detective so you get the IAM user/role profile, related findings, and unusual API sequences pre-joined. Scope investigations by agent role name prefixes and session tags. Export timelines to tickets; revoke with
AWSRevokeOlderSessions. Related: GuardDuty, CloudTrail Lake, SCPs, Budgets.
Why GuardDuty alone is not an investigation
GuardDuty is a detector. It scores a finding and points at a resource. Coding-agent incidents are multi-hop by design:
- Task role credentials leave the sandbox (SSRF, log leak, prompt injection)
- Attacker calls
sts:AssumeRoleinto a wider tool role - S3 List/Get on artifact prefixes, Bedrock
InvokeModel, maybe EC2 in a new region - Optional: disable logging / create persistence keys
Each hop is a separate finding or a quiet CloudTrail row. Detective’s job is to group those into one investigation story and show you the baseline (“this role usually only calls S3 + Bedrock in us-east-1”) versus the anomaly (“sudden CreateAccessKey + RunInstances in ap-south-1”).
| Layer | Question it answers | Agent use |
|---|---|---|
| GuardDuty | Is this bad? | Page + auto-revoke |
| Detective | How did it spread? | Graph + timeline |
| CloudTrail Lake | Exact API autopsy | Custom SQL |
| Macie / Security Hub | What data / org-wide view | Secrets + aggregation |
Enable Detective for agent OUs
Use Organizations so every sandbox and prod agent account feeds the same Detective behavior graph. Detective needs GuardDuty enabled in the account (it consumes findings) plus CloudTrail management events and VPC Flow Logs for richer profiles.
# ✅ enable Detective (member accounts via Org preferred)
aws detective create-graph --tags Key=workload,Value=coding-agent
# ✅ list graphs / confirm member accounts
aws detective list-graphs
aws detective list-members --graph-arn "$GRAPH_ARN"
// ✅ CDK sketch: enable Detective + tag for agent fleet ownership
import * as detective from "aws-cdk-lib/aws-detective";
const graph = new detective.CfnGraph(this, "AgentDetectiveGraph", {
tags: [{ key: "workload", value: "coding-agent" }],
});
// Prefer Organizations auto-enable in production — do not hand-roll per account forever
❌ Standing up Detective in only the “security” account while agent sandboxes stay dark: you will investigate the wrong blast radius.
From GuardDuty finding → Detective investigation
The unfair advantage is the pivot: open the finding in Detective (console deep-link or API), not in a generic SIEM dump.
# ✅ start from a GuardDuty finding ID and pull Detective entity profile hints
import boto3
gd = boto3.client("guardduty")
det = boto3.client("detective")
def investigate_agent_finding(detector_id: str, finding_id: str, graph_arn: str):
finding = gd.get_findings(DetectorId=detector_id, FindingIds=[finding_id])["Findings"][0]
# Entity of interest for credential exfil is usually the IAM principal / access key
ak = finding.get("Resource", {}).get("AccessKeyDetails", {})
user_name = ak.get("UserName")
access_key_id = ak.get("AccessKeyId")
# ❌ Do not stop at revoke — collect the related finding group first
print({
"type": finding["Type"],
"severity": finding["Severity"],
"userName": user_name,
"accessKeyId": access_key_id,
"account": finding["AccountId"],
"graph": graph_arn,
"next": "Open IAM role/user profile in Detective; review Finding groups + New behavior",
})
return finding
In the Detective console for that role:
- Overall API call volume vs baseline
- New geolocations / user agents (attacker laptop vs Fargate UA)
- Related findings in the same finding group (S3 exfil + anomalous EC2)
- Resource interactions — which buckets/prefixes, which KMS keys
For agent fleets, filter mental model by role name prefix (coding-agent-*) and by aws:PrincipalTag/tenant_id if you stamp session tags on AssumeRole (IAM condition keys pattern).
Playbook: compromised coding-agent credentials
- Contain — delete access keys / invalidate role sessions (
AWSRevokeOlderSessionson role trust); kill tool via AppConfig - Investigate in Detective — open GuardDuty finding → role profile → finding group → note first anomalous API time
- Confirm with Lake — SQL for that principal’s 24h API set (CloudTrail Lake)
- Data impact — Macie jobs on touched prefixes; check Object Lock / versioning for overwrite attempts
- Hardening — tighten SCPs, reduce task-role permissions, enable Network Firewall egress allowlists
-- ✅ CloudTrail Lake follow-up after Detective shows first bad eventTime
SELECT eventTime, eventName, sourceIPAddress, userAgent,
requestParameters, errorCode
FROM agent_trail_lake
WHERE userIdentity.sessionContext.sessionIssuer.arn LIKE '%coding-agent-tool%'
AND eventTime BETWEEN timestamp '2026-09-26 08:00:00' AND timestamp '2026-09-26 12:00:00'
ORDER BY eventTime ASC
LIMIT 1000
// ✅ force session invalidation on the agent tool role trust policy
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": "sts:AssumeRole",
"Principal": {"AWS": "*"},
"Condition": {
"StringEquals": {"aws:PrincipalTag/workload": "coding-agent"},
"DateLessThan": {"aws:TokenIssueTime": "2026-09-26T10:15:00Z"}
}
}]
}
(Use the console/API “revoke older sessions” pattern — the AWSRevokeOlderSessions inline deny — rather than inventing fragile hand-rolled trusts.)
Finding groups vs single findings
Detective finding groups are where agent incidents shine. A lone GuardDuty informational finding is noise. A group that ties:
- credential exfil
- anomalous S3 GetObject volume
CreateKeyPair/RunInstances
…is a campaign. Train on-call to open the group, not acknowledge findings one-by-one in Jira.
| Symptom in Detective | Likely agent story | Next action |
|---|---|---|
| New UA + geo on task role | Stolen keys used from laptop | Revoke + rotate forge secrets |
| Spike S3 Get on many prefixes | Artifact bucket dump | Quarantine bucket; Macie scan |
| Bedrock InvokeModel surge | Prompt abuse / cost attack | Kill switch + Budgets alarm |
| IAM CreateUser from agent role | Persistence attempt | SCP deny; page security |
Production checklist
- [ ] Detective graph enabled Org-wide; agent accounts are members
- [ ] GuardDuty findings openable into Detective (same Region)
- [ ] On-call runbook: GuardDuty HIGH → contain → Detective group → Lake SQL
- [ ] Agent roles tagged (
workload=coding-agent,tenant_id=…) for filterability - [ ] Session revoke tested quarterly on a canary role
- [ ] SCPs deny standing
CreateAccessKey/ logging disable in agent OUs (SCPs) - [ ] Findings + investigation notes retained ≥ 90 days for audit
- [ ] Dual-signal: Detective graph + Budgets/Cost Anomaly when spend spikes with findings
FAQ
Q: Is Detective a replacement for a SIEM?
A: No. It is the AWS-native investigation graph for GuardDuty-centric incidents. Export to your SIEM; use Detective when the finding is AWS-entity-heavy (IAM, S3, EC2, EKS).
Q: Do I need Detective if I already have CloudTrail Lake?
A: Lake is powerful but cold-start. Detective precomputes baselines and finding groups so you do not invent joins under pager pressure. Use both.
Q: How long until baselines are useful?
A: Detective needs a short warm-up of telemetry (days). Enable it before the incident — enabling mid-breach does not rewrite history.
Related reading
- Amazon GuardDuty: Catch Compromised Coding-Agent Credentials Early
- CloudTrail Lake: Query Agent IAM Abuses
- Amazon Macie: Scan Coding-Agent Artifact Buckets
- AWS Organizations SCPs: Hard Caps for Coding-Agent Accounts
Detective is the investigation layer that makes GuardDuty pages actionable for coding-agent fleets: graph the hops, revoke the right sessions, and prove what the attacker touched — then harden so the next finding never becomes a week-long mystery.
Last updated on September 26, 2026
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
- Spec-First AI Development: OpenAPI Remains the Only Source of Truth
- Java Virtual Threads vs Traditional Threads: What Nobody Tells You
- Distributed Locks Reality Check: When Redis Redlock Is the Wrong Tool
Newly added
- Amazon Bedrock Model Evaluation: Score Coding-Agent Outputs Before You Promote a Prompt
- AWS App Runner: Host Coding-Agent HTTP APIs Without Babysitting Containers
- Amazon S3 Object Lock: Immutable Artifact Buckets Coding Agents Cannot Overwrite
- AWS Security Hub: Aggregate Coding-Agent Security Findings Across Accounts
- Amazon Detective: Investigate Compromised Coding-Agent Credentials After GuardDuty
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.