Your agent uploaded turn-8842-debug.tgz to the shared artifacts bucket — inside it: a .env from the customer repo, a GitHub PAT in a failing test log, and a screenshot of an IAM console. Nobody will open that tarball until a breach review. Amazon Macie is the unfair advantage for agent artifact stores: managed discovery jobs that classify secrets and sensitive data in S3 so you quarantine and rotate before the next sync job fans the object out. Pair with Secrets Manager rotation and S3 conditional writes — this post is the bucket scanning layer.
⚡ TL;DR: Run Macie discovery on every coding-agent artifact / eval / log bucket. Alert on AWS keys, private keys, and custom PAT detectors; auto-quarantine objects and rotate matching secrets. Prefer prevent (guardrails, .gitignore, pre-upload scanners) + detect (Macie). Related: GuardDuty credentials, CloudTrail Lake, CodeArtifact, Budgets.
Why agent buckets are secret landfills
Coding agents write a lot of semi-structured junk:
- Patch files and worktrees (may include
.env.local) - CI logs and pytest output (echoed tokens)
- Model traces and tool payloads (prompts with pasted secrets)
- Eval corpora copied from customer monorepos
Traditional DLP assumes curated document stores. Agent buckets look like /tenants/*/turns/*/. Macie is built for S3-scale discovery with managed + custom data identifiers.
| Store | Secret risk | Macie fit |
|---|---|---|
| Artifact S3 | ✅ High | ✅ Primary |
| CloudWatch Logs | ✅ High | Use Logs + Insights; export hot paths to S3 for Macie |
| EFS workspaces | ✅ High | Snapshot/sync samples to S3 for scan (EFS post) |
| DynamoDB sessions | Medium | App-level redaction; not Macie’s home turf |
| ECR images | Medium | Image scanning + avoid baking .env (ECR+Lambda) |
Turn on Macie and scope discovery jobs
Enable Macie per account (or Org), then define jobs that target only agent buckets — do not burn budget classifying unrelated data lakes on day one.
# ✅ enable Macie
aws macie2 enable-macie
# ✅ discovery job: daily on agent artifacts prefix
aws macie2 create-classification-job \
--name coding-agent-artifacts-daily \
--job-type SCHEDULED \
--schedule-frequency '{"dailySchedule":{}}' \
--s3-job-definition '{
"bucketDefinitions":[{
"accountId":"111122223333",
"buckets":["coding-agent-artifacts-prod"]
}],
"scoping":{
"includes":{"and":[{
"simpleScopeTerm":{
"comparator":"STARTS_WITH",
"key":"OBJECT_KEY",
"values":["tenants/"]
}
}]}
}
}' \
--managed-data-identifier-selector ALL
// ✅ custom data identifier for GitHub PATs / npm tokens (illustrative regex)
new macie.CfnCustomDataIdentifier(this, "GithubPat", {
name: "github-pat-agent",
regex: "ghp_[A-Za-z0-9]{20,}",
description: "GitHub personal access tokens in agent artifacts",
maximumMatchDistance: 50,
keywords: ["github", "ghp_", "token"],
});
Findings → quarantine → rotate
Macie findings alone do not rotate secrets. Wire EventBridge:
# ✅ on sensitive finding: tag object quarantine + rotate likely secret
import boto3
s3 = boto3.client("s3")
sm = boto3.client("secretsmanager")
QUARANTINE = {"Key": "quarantine", "Value": "macie-sensitive"}
def handle_macie_finding(detail: dict):
resources = detail.get("resourcesAffected", {})
s3obj = resources.get("s3Object", {})
bucket = s3obj.get("bucketArn", "").split(":")[-1]
key = s3obj.get("key")
if not bucket or not key:
return
s3.put_object_tagging(
Bucket=bucket,
Key=key,
Tagging={"TagSet": [QUARANTINE, {"Key": "macieFindingId", "Value": detail.get("id", "")[:64]}]},
)
# deny GETs via bucket policy on quarantine=macie-sensitive (separate)
severity = detail.get("severity", {}).get("description")
# ✅ heuristic: if AWS secret key identifier matched, rotate agent AWS-adjacent secrets
for detection in detail.get("classificationDetails", {}).get("result", {}).get("sensitiveData", []) or []:
for d in detection.get("detections", []):
if d.get("type") in ("AWS_CREDENTIALS", "PRIVATE_KEY"):
sm.rotate_secret(SecretId="agent/shared/emergency-rotate-hook")
return {"quarantined": f"s3://{bucket}/{key}", "severity": severity}
// ✅ bucket policy fragment: block reads of quarantined objects except IR role
{
"Effect": "Deny",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::coding-agent-artifacts-prod/*",
"Condition": {
"StringEquals": {"s3:ExistingObjectTag/quarantine": "macie-sensitive"},
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::111122223333:role/ir-*"}
}
}
Prevent as much as you detect
Macie is your backstop. Up-stack controls:
- Pre-upload secret scan in the sandbox (gitleaks/trufflehog) before
aws s3 cp - Strip tool I/O with Bedrock ApplyGuardrail
- Never persist raw prompts with secrets — hash or redact in Step Functions result writers
- Tenant-prefix IAM so one role cannot list all artifacts
| Control | When it fires | Gap |
|---|---|---|
| Pre-upload scanner | Before S3 put | Bypass if agent skips hook |
| Guardrails | Model/tool boundary | Binary artifacts |
| Macie | After object lands | Hours of exposure window |
| GuardDuty | Credential use | Silent unused leak |
Cost and sampling strategy
Macie pricing follows bytes classified. For huge eval dumps:
- Exclude known-safe extensions (
*.pyc,node_modulesmirrors — better: do not upload them) - Sample historical prefixes; always-scan
tenants/*/turns/*/logs/ - Watch Budgets for Macie spend anomalies after a tenant floods artifacts
# ❌ uploading entire node_modules to artifacts "for debug"
tar -czf /tmp/debug.tgz /work/repo # includes secrets + megabytes Macie will bill
aws s3 cp /tmp/debug.tgz s3://artifacts/tenants/$T/turns/$TURN/
# ✅ allowlisted paths only
tar -czf /tmp/debug.tgz /tmp/pytest.log /tmp/patch.diff
aws s3 cp /tmp/debug.tgz s3://artifacts/tenants/$T/turns/$TURN/debug.tgz
Production checklist
- [ ] Macie enabled in every account that holds agent artifacts
- [ ] Scheduled discovery on artifact + eval buckets; custom identifiers for forge PATs
- [ ] EventBridge → quarantine tag + IR notify + Secrets Manager rotate hook
- [ ] Bucket policy denies GetObject on quarantined tags except IR roles
- [ ] Pre-upload secret scanning in sandbox images
- [ ] Guardrails on tool I/O; no raw secret prompts to durable storage
- [ ] Macie findings reviewed weekly; false-positive identifiers tuned
- [ ] Correlate with CloudTrail Lake who PutObject’d the offender
What “sensitive” should mean for coding agents
Tune managed identifiers so you care about:
- AWS access keys and secret keys
- Private keys (PEM)
- Creds that match your forge/npm/pypi custom regexes
- Customer PII if eval corpora may contain it
Noise like public README emails should not page IR. Start with HIGH severity credential types → auto quarantine, and route PII/medium findings to a weekly security review queue. That split keeps Macie actionable instead of another ignored dashboard.
FAQ
Q: Can Macie scan EFS directly?
A: No — copy or sync risk paths to S3 for classification, or run offline scanners on the mount in a locked-down job (EFS workspaces).
Q: Is Macie a replacement for Secrets Manager?
A: No. Secrets Manager stores and rotates; Macie finds copies that escaped into objects.
Q: How fast will we know?
A: Job cadence bound (daily/continuous). For zero-minute ambitions, rely on pre-upload scanners; Macie catches what slipped through.
Macie turns coding-agent artifact buckets from unaudited landfills into continuously classified stores. Quarantine on finding, rotate on credential types, and keep uploading boring — small allowlisted artifacts beat giant “debug” tarballs every time.
Multi-account rollout without boiling the ocean
Most CheatCoders-style fleets already have a security tooling account and many agent sandbox accounts. Recommended shape:
- Delegate Macie admin to the security account
- Auto-enable Macie on agent OUs via Organizations
- Central findings bucket / EventBridge bus in security account
- Per-sandbox jobs only on that account’s artifact buckets (avoid cross-account classify storms on day one)
When a finding references tenants/acme/..., page the tenant owner channel and disable the uploading tool via AppConfig until the path is clean. If the same tenant repeats, enforce stronger pre-upload gates in their Fargate Spot task definition (init container scanner required). Pair repeated AWS-key findings with the GuardDuty playbook — Macie found the copy; GuardDuty catches the use.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Spec-First AI Development: OpenAPI Remains the Only Source of Truth
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
- Distributed Locks Reality Check: When Redis Redlock Is the Wrong Tool
- Python asyncio vs Threading: The Benchmark That Changes How You Think About Concurrency
Newly added
- AWS IAM Roles Anywhere: Cert-Based Creds for On-Prem Coding-Agent Runners
- Amazon Macie: Scan Coding-Agent Artifact Buckets for Leaked Secrets
- Amazon GuardDuty: Catch Compromised Coding-Agent Credentials Early
- AWS Network Firewall: Egress Filtering for Coding-Agent Sandboxes
- Amazon RDS Proxy: Connection Pooling for Coding-Agent Database Tools
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.