DEV Community

akihito
akihito

Posted on

field-cage: a local-first alternative for GitHub Actions egress control

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:

  1. Explicit IPv4, IPv6, and CIDR entries.
  2. A/AAAA records resolved for configured domains at startup.
  3. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Run normal build, test, and release paths in audit mode.
  2. Review the observed destinations.
  3. Create the smallest practical allowlist.
  4. 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)