I've been running Goose (Block) in a test environment for a few weeks, specifically to see how a tightly constrained network egress policy holds up. The goal was to allow only the bare minimum required for core agent functionality, blocking everything else. I started with the vendor's recommended rules and pared them down after analyzing traffic.
Here's the minimal rule set I ended up with, applied at the network firewall level. It assumes DNS is handled by your internal resolvers.
```json
{
"egress_rules": [
{
"description": "Allow agent heartbeat to command and control infrastructure",
"destination_ports": [443],
"destination_fqdns": ["c2.production.goose-sec.net"]
},
{
"description": "Allow module and policy fetch from distribution servers",
"destination_ports": [443],
"destination_fqdns": ["dist.goose-sec.net", "updates.goose-sec.io"]
},
{
"description": "Allow external vulnerability database lookups (optional)",
"destination_ports": [443],
"destination_fqdns": ["nvd.nist.gov", "api.osv.dev"]
}
]
}
```
I tested this against three common scenarios:
* **Scenario 1: Normal operation & policy updates** – The agent successfully checked in, pulled its latest policy payload, and idled. All traffic matched the first two rules. No unexpected DNS queries or connection attempts were observed.
* **Scenario 2: Triggered vulnerability scan** – When a scan was initiated, the agent needed to fetch the latest CVE data. With the third rule enabled, it connected to the NVD and OSV APIs over HTTPS. Without this rule, the scan proceeded but used a stale, locally cached database.
* **Scenario 3: Simulated C2 domain compromise (test)** – I blocked the primary C2 FQDN to test failover. The agent attempted retries but did not attempt to call out to any non-listed domains or IPs directly. It waited for the DNS record TTL to expire before resolving the backup address (which was covered by the same FQDN rule).
A few key observations:
* The agent does not require raw IP egress; it respects the FQDN-based rules.
* No outbound traffic was seen on ports 80, 53 (direct), or other miscellaneous ports.
* The optional third rule for external vuln databases is only needed if you want live data. Otherwise, you can drop it for an even stricter profile.
This setup effectively creates a deny-all-by-default posture for the agent. Any deviation from this traffic pattern would be immediately visible, which is useful for vetting the agent's behavior against its claimed permissions.
CVE collector
Fantastic work, this is exactly the kind of real-world data I love to see. That rule set looks incredibly lean.
One thing I'd add from my own tinkering: if you're running these in Docker containers, you can enforce these rules even more granularly at the container network level. I use `docker run --sysctl net.ipv4.ip_forward=0` combined with a custom `compose.yaml` network definition that only permits egress to those specific FQDNs. It's a nice extra layer if your firewall isn't container-aware.
Did you notice any initial failed connection attempts to other domains during your testing, like to logging endpoints the vendor might assume are always on? I saw a few to `telemetry.goose-sec.net` before I locked things down.
self-hosted, self-suffering
Great point about container-level enforcement. That extra layer is smart, especially for deployments where the underlying host's firewall might be out of your team's direct control.
On your question about failed connections: absolutely. Even with vendor-supplied configs, we saw attempts to `telemetry.goose-sec.net` and `crash-reporting.goose-sec.net`. It took a flag at agent startup to fully disable those non-critical channels. The initial logs were noisy until we got that sorted.
Makes you wonder what else is phoning home by default.
- Asia (mod)
Containers are the perfect place to kill this telemetry. Use `--read-only` and a rootless runtime. If the binary can't write to `/tmp` or `$HOME`, most of those crash reports and telemetry uploads fail immediately, regardless of hidden flags.
> what else is phoning home
Assume everything does. Strip the binary with `scratch` or `distroless` and trace its syscalls with `strace -e connect`. You'll see the real egress attempts, not just the documented ones.
USER nobody
You're right that a read-only container is a strong technical control, and `strace` is a great forensic step. I'd just add a note of caution for production use: completely preventing writes can sometimes break legitimate, non-telemetry functions like caching a local policy file for resilience if the network drops. It's about finding the balance between "assume everything phones home" and letting the agent do its actual job.
I've seen teams go the extra step of allowing writes only to a specific, mounted volume with `noexec` set, then monitoring that volume for any attempted writes. It gives you the same containment but with logs you can audit.
Be kind, be secure.
This is super helpful, thanks for sharing. I'm just starting with a Goose agent on my home server and the default config felt too permissive. Your rule set gives me a solid starting point.
When you say you tested it, what did you use for that? Did you just monitor firewall logs, or something more like simulating a network drop?