I built field-cage, an MIT-licensed eBPF agent that monitors and restricts outbound connections from Linux GitHub Actions runners.
It overlaps with StepSecurity Harden-Runner, but has a deliberately smaller scope. Harden-Runner is a CI/CD runtime security platform; field-cage is an egress filter. It uses explicit policies, keeps reporting local, and requires no hosted backend.
field-cage is free to use in private repositories. There is no account, license key, subscription, or repository-visibility check: the same audit, block, and reporting functionality is available under the MIT license for both public and private repositories.
field-cage and Harden-Runner
Both tools can observe outbound connections and block destinations not permitted by policy. The main difference is how much infrastructure and security context they provide around that control.
| Area | field-cage | Harden-Runner |
|---|---|---|
| Primary scope | Network egress | CI/CD runtime security |
| Events | Network connections and DNS responses | Network, process, and file activity |
| Policy | Explicit domain, IP, and CIDR allowlist | Egress policy, behavioral baselines, and managed threat intelligence |
| Reporting | Local log, CLI formats, optional job summary | Per-run insights and centralized management |
| External service | Not required | Used for the complete platform experience |
| Platforms | Linux runners with eBPF support | Linux; GitHub-hosted Windows and macOS also have audit support |
| Private repositories | Free; same MIT-licensed functionality as public repositories | Enterprise tier |
| Self-hosted runners | Supported when Linux, privileges, and eBPF requirements are met | Enterprise tier with VM, bare-metal, and ARC support |
Harden-Runner also detects source-code tampering, correlates events with individual workflow steps, tracks process execution and file writes, recommends permissions, and provides organization-wide visibility. field-cage does none of those things.
That is the trade-off. Harden-Runner is the stronger choice when a security team needs a managed, multi-repository runtime security system. field-cage is aimed at the narrower requirement: “this job may connect only to these destinations.”
Private repositories without a paid tier
This is one of the practical differences between the two projects. Harden-Runner's Community tier is intended for public repositories; private-repository support is part of its paid Enterprise offering.
field-cage does not have separate Community and Enterprise editions. A private company repository can use the same egress monitoring and default-deny enforcement as a public open-source repository, without sending security events to a vendor service. The trade-off is that field-cage does not provide Harden-Runner's centralized dashboard, managed threat intelligence, organization-wide policy, or enterprise support.
How field-cage enforces the policy
In block mode, field-cage attaches eBPF programs to cgroup/connect4 and cgroup/connect6. A connection is allowed only if its destination is present in an eBPF LPM trie; otherwise the kernel returns EPERM.
The allowlist is populated from:
- Explicit IPv4, IPv6, and CIDR entries.
- A/AAAA records resolved for configured domains at startup.
- DNS responses observed while the job runs.
A socket filter observes DNS responses so that IP addresses can be mapped back to domains. Only responses from resolvers configured in /etc/resolv.conf or from loopback may extend the kernel allowlist.
mode: block
allow_all_dns: false
allowlist:
- github.com
- api.github.com
- objects.githubusercontent.com
- registry.npmjs.org
- 10.0.0.0/8
- 2001:db8::/32
Wildcard domains are intentionally unsupported. Each permitted destination remains visible in code review. Unknown YAML keys are rejected rather than silently ignored.
field-cage has two modes:
- Audit records connection attempts without blocking them.
- Block applies default-deny enforcement to IPv4 and IPv6 connections.
Logs remain on the runner unless the workflow explicitly uploads them. They can be rendered as text, JSON, CSV, or a GitHub Actions job summary.
GitHub Actions usage
- uses: takihito/field-cage@v0.1.0
with:
version: v0.1.0
mode: audit
allow: |
github.com
api.github.com
objects.githubusercontent.com
registry.npmjs.org
The composite Action downloads the selected release binary, verifies its SHA-256 checksum, and starts the agent in the background. For production use, the uses: reference should be pinned to a full commit SHA.
The intended rollout is audit first, then block:
- Run normal build, test, and release paths in audit mode.
- Review the observed destinations.
- Create the smallest practical allowlist.
- Switch to block mode and review later policy changes as code.
The Action should run near the beginning of the job. Unlike Harden-Runner's broader job-level integration, field-cage cannot observe connections made before its setup step.
Where Harden-Runner has the advantage
Harden-Runner is more mature and covers substantially more than egress filtering:
- process execution and file-write monitoring;
- correlation with workflow steps;
- historical network baselines and anomaly detection;
- maintained indicators for active supply-chain attacks;
- centralized visibility across repositories and runners;
- Windows and macOS audit coverage;
- enterprise support and governance.
If those capabilities are required, field-cage is not a replacement.
Where field-cage fits
field-cage may be useful when you prefer:
- free egress monitoring and blocking for private repositories;
- a small, inspectable, fully static Go binary;
- explicit network policy stored with the repository;
- no required vendor dashboard or telemetry backend;
- local logs that leave the runner only when configured to do so;
- a standalone agent that can also run outside GitHub Actions.
The simpler architecture also means less automation. field-cage does not generate historical baselines or decide whether an observed destination is legitimate. Policy ownership remains with the repository maintainer.
Limits
field-cage requires Linux, eBPF support, and sufficient privileges. It is not a hard isolation boundary against an attacker who already controls the runner as root and can detach its eBPF programs.
Domain-based enforcement also has unavoidable edge cases. A first connection can race with a newly observed DNS response; field-cage fails closed, so the connection is denied until a retry. Live observation currently covers plaintext UDP DNS over IPv4, not DNS over TCP, IPv6 transport, DoH, or DoT. Queries through a legitimate resolver can still be used as a low-bandwidth DNS tunnel.
These constraints are documented because the project is meant to provide a predictable network control, not the impression of a complete CI/CD security boundary.
Distribution
Release binaries are fully static and published for Linux amd64 and arm64. The Action verifies SHA-256 checksums, and releases include a cosign keyless signature bundle and SLSA Level 3 provenance.
I would be interested in feedback on whether this narrower, local-first approach—particularly free use in private repositories—is useful compared with a more comprehensive system such as Harden-Runner.
Top comments (0)