Your coding-agent sandbox just curl’d an attacker-controlled URL from a poisoned README, uploaded the monorepo tarball, and still passed unit tests. Open NAT gateways are the default for “make npm install work” — and the default blast radius when a tool is jailbroken. AWS Network Firewall is the unfair advantage for agent sandboxes: managed Suricata inspection on the egress path, domain allowlists, and centralized deny rules without rewriting every task definition. Pair with PrivateLink for Bedrock so model calls never need the internet, and CodeArtifact so packages never need npmjs.org — this post is the egress filter layer.
⚡ TL;DR: Route sandbox subnet egress through Network Firewall with deny-by-default + allowlist for git forges, CodeArtifact, and approved APIs. Keep Bedrock on PrivateLink (no NAT). Log matches to S3/CloudWatch; alert on blocked C2-shaped traffic. Related: Fargate Spot sandboxes, WAF rate-limits, SCPs, Secrets Manager.
Why sandbox egress is different from app egress
App backends usually need a predictable set of SaaS APIs. Coding-agent sandboxes:
- Clone arbitrary customer repos (git over HTTPS/SSH)
- Install packages (npm/pip/maven — ideally mirrored)
- Call model/tool APIs inside your VPC
- Are prompt-injection targets — they will try surprise destinations
Security groups alone cannot filter by domain. NACLs are too coarse. Network Firewall inspects L3–L7 on the path from sandbox subnets to the internet (or to other VPCs).
| Control | Domain allowlist | TLS SNI / HTTP host | Central policy | Agent fit |
|---|---|---|---|---|
| Security groups | ❌ | ❌ | Per-ENI | Baseline only |
| NAT + SG | ❌ | ❌ | Weak | Default footgun |
| Network Firewall | ✅ | ✅ Suricata | ✅ | Sandbox egress |
| PrivateLink only | N/A | N/A | Per-service | Prefer for AWS APIs |
| Squid on EC2 | ✅ DIY | ✅ DIY | Ops heavy | Legacy |
Reference architecture for agent sandboxes
- Sandbox subnets (Fargate Spot / CodeBuild / Batch): no IGW route;
0.0.0.0/0→ Firewall endpoint - Firewall subnets: Network Firewall endpoints
- Egress subnets: NAT Gateway only after Firewall allow
- AWS APIs: Interface VPC endpoints / PrivateLink — never hairpin through Firewall to the public AWS endpoint if you can avoid it
// ✅ CDK: firewall policy allowlist for coding-agent sandboxes
import * as networkfirewall from "aws-cdk-lib/aws-networkfirewall";
const allowDomains = new networkfirewall.CfnRuleGroup(this, "AgentAllowDomains", {
ruleGroupName: "coding-agent-egress-allow",
type: "STATEFUL",
capacity: 100,
ruleGroup: {
rulesSource: {
rulesSourceList: {
generatedRulesType: "ALLOWLIST",
targetTypes: ["HTTP_HOST", "TLS_SNI"],
targets: [
".github.com",
".githubusercontent.com",
".gitlab.com",
// ✅ prefer CodeArtifact endpoint over public registries
`codeartifact.${region}.amazonaws.com`,
],
},
},
},
});
const denySuspicious = new networkfirewall.CfnRuleGroup(this, "AgentDenySuricata", {
ruleGroupName: "coding-agent-egress-deny",
type: "STATEFUL",
capacity: 50,
ruleGroup: {
rulesSource: {
// ❌ block raw IP HTTPS often used in exfil; tune carefully for git SSH if needed
rulesString: `
drop tls $HOME_NET any -> $EXTERNAL_NET any (msg:"agent drop non-SNI tls"; tls.sni; sid:1001; rev:1;)
`,
},
},
});
const policy = new networkfirewall.CfnFirewallPolicy(this, "AgentFwPolicy", {
firewallPolicyName: "coding-agent-sandbox",
firewallPolicy: {
statelessDefaultActions: ["aws:forward_to_sfe"],
statelessFragmentDefaultActions: ["aws:forward_to_sfe"],
statefulRuleGroupReferences: [
{ resourceArn: allowDomains.attrRuleGroupArn, priority: 10 },
{ resourceArn: denySuspicious.attrRuleGroupArn, priority: 20 },
],
statefulDefaultActions: ["aws:drop_established", "aws:alert_established"],
},
});
# ✅ verify sandbox cannot hit random egress (from inside task)
curl -sS -o /dev/null -w "%{http_code}\n" https://evil.example --max-time 5
# expect hang/fail — Firewall drop
# ✅ approved forge still works
git ls-remote https://github.com/org/repo.git HEAD
Package installs without opening the world
Deny-by-default breaks npm install against the public registry — that is the point. Mirror packages through CodeArtifact and allow only the CodeArtifact domain / VPC endpoint. Same pattern for pip (CodeArtifact PyPI upstream) and Maven.
// ✅ .npmrc in sandbox image
{
"registry": "https://ORG-DOMAIN-ACCOUNT.d.codeartifact.REGION.amazonaws.com/npm/agent-store/",
"//ORG-DOMAIN-ACCOUNT.d.codeartifact.REGION.amazonaws.com/npm/agent-store/:_authToken": "${CODEARTIFACT_AUTH_TOKEN}"
}
❌ Baking registry.npmjs.org into the allowlist “just for one package” recreates the exfil path via typosquatting and postinstall scripts.
Bedrock, secrets, and north-south vs east-west
- Model calls: PrivateLink Bedrock — remove Bedrock from NAT entirely
- Secrets: fetch via VPC endpoint to Secrets Manager, never from public
- Public agent HTTP APIs still need WAF on the north-south edge — Firewall is primarily sandbox egress (southbound)
Complement with SCPs that deny ec2:CreateInternetGateway attachments in agent OUs so teams cannot bypass the Firewall VPC.
Logging and response
Enable Firewall alert/flow logs to CloudWatch or S3. Pipe high-severity drops into CloudWatch Logs Insights queries tagged by tenant_id / turn_id (add custom dimensions via flow log enrichment or sidecar). On sudden allowlist miss storms after a prompt change, flip an AppConfig kill switch for the offending tool.
| Signal | Meaning | Action |
|---|---|---|
| Spike TLS SNI drops | Injection / bad dependency | Quarantine tenant; review tool IO (Guardrails) |
| CodeArtifact 403 + no Firewall drop | IAM/token issue | Fix auth, not allowlist |
| All git failing | Over-tight allowlist | Add forge domains carefully |
| NAT bytes ↑ Firewall bytes ↓ | Route table bypass | Fix subnet routes |
Production checklist
- [ ] Sandbox
0.0.0.0/0points at Firewall endpoints, not straight to NAT - [ ] Stateful default = drop established; explicit ALLOWLIST for forges + mirrors
- [ ] Bedrock/Secrets/STS/ECR via PrivateLink / VPC endpoints
- [ ] CodeArtifact (or other private mirror) required for package installs
- [ ] Alert + flow logs retained; Insights queries for deny storms
- [ ] SCPs prevent IGW/NAT shortcuts in agent accounts
- [ ] Document break-glass allowlist change with dual control
- [ ] Fargate Spot / CodeBuild task ENIs only in sandbox subnets
FAQ
Q: Is Network Firewall overkill vs squashing security groups?
A: SGs cannot see evil.example. Once agents execute untrusted code/docs, you need domain-aware egress.
Q: What about SSH git on port 22?
A: Prefer HTTPS git with PATs from Secrets Manager, or allowlist forge IPs carefully — raw any:22 recreates exfil.
Q: Does this replace WAF?
A: No. WAF protects public entrypoints; Firewall constrains what sandboxes can call out to.
Network Firewall turns coding-agent sandboxes from “NAT and pray” into deny-by-default egress with an allowlist you can audit. Mirror packages, PrivateLink your AWS APIs, and treat every surprise SNI drop as a security signal — not a connectivity ticket.
Rollout pattern that does not brick CI overnight
Do not flip deny-by-default on day one across every tenant. Stage it:
- Alert-only stateful rules for two weeks — measure which SNIs sandboxes actually need
- Publish a per-team allowlist proposal from Firewall logs (forges, mirrors, internal APIs)
- Enforce on a canary OU / AppConfig-flagged tenants
- Expand OU-wide under SCPs that forbid route-table bypasses
# ✅ sample Insights-style filter over Firewall alert logs (adjust fields to your schema)
fields @timestamp, event.event_timestamp, event.src_ip, event.dest_ip, event.alert.signature
| filter event.alert.action = "blocked"
| stats count() by event.alert.signature
| sort count desc
Teams that “need the whole internet for browsershots” should run those tools in a separate VPC with a different risk tier — not punch holes in the coding-agent sandbox Firewall. Keep clone/test/apply fleets boring and locked down; isolate high-egress research agents where you can afford the blast radius.
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.