A GitHub Action for egress filtering and runner lockdown.
Add Fence as the first step in a GitHub-hosted Linux job:
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: openai/fence@<commit-sha> # pin@vX.Y.Z
- uses: actions/checkout@<checkout-commit-sha>
- run: script/testCopy the full commit SHA and version comment from the latest verified release. Fence supports GitHub-hosted ubuntu-24.04 and ubuntu-latest x64 runners.
By default, Fence:
- Blocks outbound connections unless the hosted runner needs them or you allow them.
- Turns off passwordless
sudo. - Turns off Docker and container access.
- Reports network activity in the job summary and logs.
See Getting started for a complete example.
Add destinations your workflow needs to the allowlist:
- uses: openai/fence@<commit-sha> # pin@vX.Y.Z
with:
allowlist: |
api.example.com
registry.example.com:8443
udp://dns.example.com:53
ip 192.0.2.10 tcp 443
cidr 192.0.2.0/24 udp 123Bare hostnames default to TCP port 443. Fence also supports IPv6, custom ports, TCP, UDP, CIDR ranges, and one- or two-level hostname wildcards. An allowlist can contain up to 64 unique entries.
In block mode, Fence can shorten DNS cache lifetimes to match its firewall rules. Allowlist the hostname, not each IP it resolves to.
See allowlist syntax for all supported formats.
Not sure what your workflow needs? Start with audit mode:
- uses: openai/fence@<commit-sha> # pin@vX.Y.Z
with:
mode: auditAudit mode shows what Fence would block while leaving network, sudo, and Docker access available. For example, if DNS requests exceed the user wildcard hostname limit, audit forwards them and reports what block mode would deny. It may still restore root ownership of /etc and /usr. Use the job summary to build your allowlist, then switch back to block mode.
On supported runners, Fence accepts normal Ubuntu UUID service activation (for example, by az version) in audit and block modes. Incomplete socket observations or unexpected owners still fail the job.
Artifact uploads, GitHub Pages, and caches sometimes need access to storage endpoints used by GitHub Actions:
- uses: openai/fence@<commit-sha> # pin@vX.Y.Z
with:
allow_github_artifacts: trueImportant
This setting gives the job another way to send data off the runner. It is off by default; turn it on only when the job needs artifacts, Pages, or caches.
Fence disables Docker by default. If your job needs containers, you can keep it available:
- uses: openai/fence@<commit-sha> # pin@vX.Y.Z
with:
container_policy: unsafe_preserveWarning
Keeping Docker gives up containment. Later steps can use Docker to gain root access and bypass Fence's network rules.
Run Fence once per job. If setup fails, check the startup diagnostics in the job log; Fence does not copy raw service logs there. Cleanup only removes this launch's unfinished setup. It never removes another launch's protections or undoes the lockdown after Fence reports ready.
Fence runs before the rest of your job and controls which network destinations the runner can reach:
- It checks that the runner and bundled agent are supported.
- It allows required GitHub and runner connections, plus your
allowlist. - It blocks other outbound connections and turns off passwordless
sudoand Docker. - It checks that the firewall is active, not just that its rules exist, before reporting readiness and throughout the job.
- At job end, it verifies that readiness was committed and its protections are still healthy, reports network activity, and fails the job if they changed unexpectedly.
See how Fence works for more detail.
Fence briefly retries incomplete local service inspections before failing. If startup still fails, check the inspection reason codes in the log; see troubleshooting.
Failed evidence validation may include bounded, unverified diagnostics; the job still fails.
After evidence validation, Fence writes a network activity table and a FENCE_REPORT_JSON= line to the post-job log. It also adds the activity table to the job summary when available. You can fetch the report through the GitHub API:
gh api repos/OWNER/REPO/actions/runs/RUN_ID/jobs \
--jq '.jobs[] | {id, name}'
gh api repos/OWNER/REPO/actions/jobs/JOB_ID/logs \
| sed -n 's/^.*FENCE_REPORT_JSON=//p' \
| jq .The report shows network activity and warnings. In audit mode, it lists DNS names and connection IPs separately and suggests allowlist entries. You'll still see the activity when an allowlist entry can't grant access. A recent DNS match can help Fence avoid suggesting an unnecessary IP entry; it doesn't prove what block mode would allow. Some activity may be missing, and a DNS warning can mean Fence safely refused an answer. Anyone who can read the job log can read the report.
Fence counts DNS lookups for names that look like IP addresses under Other DNS names. That means a DNS query was observed, not a connection to that IP address.
See Network reports for an example.
Fence makes it harder for later workflow steps to send data to unexpected destinations or undo the runner's network restrictions. It is not a full sandbox.
- Supported runners: GitHub-hosted x64 jobs using
ubuntu-24.04orubuntu-latest. Fence checks the runner's security controls instead of rejecting routine image updates. - Built-in connections: GitHub Actions, job reporting, and the hosted runner still need a small set of GitHub and Azure connections.
- UDP: Block mode stops outgoing packets when their allowance ends, even from the same source port. Audit mode reports those packets without blocking them. Replies to allowed requests still work.
- Azure platform: Azure Instance Metadata Service remains reachable at
169.254.169.254:80. In block mode, only root-owned host sockets can reach Azure WireServer. Neither service needs an allowlist entry. - Artifacts:
allow_github_artifacts: trueallows limited access to storage used by GitHub Actions. - Docker: Fence disables Docker without changing its DNS settings. If you keep Docker available, later steps can bypass Fence.
- Release pinning: Copy the full commit SHA from the verified release notes, not from
mainor a version tag.
See the security guide for more details.
See Local development for build and test instructions. Hosted CI allows a bounded wait for complete blocked-event evidence without changing enforcement or the protected-finalization deadline.
- Getting started
- Configuration examples
- Allowlist syntax
- How Fence works
- Security guide
- Troubleshooting
- Release provenance
- CLI reference
- Security policy
- Fence v0 specification
- Threat model
- Security review
- Implementation history
- Repository settings
- Hermetic builds
Fence is released under the MIT License.
