The official GitHub Action for CargoWall — an eBPF-based network firewall for GitHub Actions runners that monitors and controls outbound connections during CI/CD runs.
Secure your GitHub Actions workflows with eBPF-based network egress filtering. Prevent supply chain attacks, block data exfiltration, and control outbound connections at the kernel level.
For concepts, architecture, and platform capabilities, see the main CargoWall repository.
- eBPF-based filtering: Uses kernel-level filtering for high performance and reliability
- Hostname filtering: Allow/deny based on domain names
- Subdomains are automatically allowed (i.e.
github.comwould also allowapi.github.com)
- Subdomains are automatically allowed (i.e.
- CIDR filtering: Allow/deny based on IP address ranges
- DNS tunneling prevention: Blocks DNS queries for non-allowed domains
- Docker support: Automatically configures Docker containers to respect firewall rules
- Sudo lockdown: Optionally restrict sudo access to prevent firewall bypass
- Graceful degradation: Warns and continues if eBPF is unavailable
- uses: code-cargo/cargowall-action@v1
with:
allowed-hosts: |
github.com
githubusercontent.com
registry.npmjs.orgname: Secure Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: code-cargo/cargowall-action@v1
with:
allowed-hosts: |
githubusercontent.com
registry.npmjs.org
- run: npm ci
- run: npm run build
- run: npm testNote: The action connects to the CodeCargo platform by default. For full integration, your job needs these permissions:
id-token: write(OIDC authentication),actions: read(correlate network events to steps), andcontents: read. Ifid-token: writeis not granted, the action will warn and continue without API integration. Setoffline: trueto skip API communication entirely.
CargoWall automatically configures Docker to use its DNS proxy, so hostname filtering works inside containers:
- uses: code-cargo/cargowall-action@v1
with:
allowed-hosts: |
docker.io
docker.com
registry.npmjs.org
- name: Build Docker image
run: docker build -t myapp .Run in audit mode to log connections without blocking them — useful for understanding your workflow's network dependencies before enforcing rules:
- uses: code-cargo/cargowall-action@v1
with:
mode: audit
allowed-hosts: |
githubusercontent.comEnable sudo lockdown to prevent subsequent steps from disabling the firewall:
- uses: code-cargo/cargowall-action@v1
with:
allowed-hosts: |
archive.ubuntu.com
sudo-lockdown: true
sudo-allow-commands: |
/usr/bin/apt-get
/usr/bin/dockerFor complex configurations, use a JSON or YAML config file:
- uses: code-cargo/cargowall-action@v1
with:
config-file: .github/cargowall.json.github/cargowall.json:
{
"rules": [
{ "type": "hostname", "value": "github.com", "action": "allow" },
{ "type": "hostname", "value": "registry.npmjs.org", "action": "allow" },
{ "type": "cidr", "value": "10.0.0.0/8", "ports": [443, 80], "action": "allow" }
]
}| Input | Description | Default |
|---|---|---|
mode |
Enforcement mode: enforce (block) or audit (log only) |
enforce |
allowed-hosts |
Allowed hostnames, one per line (auto matches subdomains) | |
allowed-cidrs |
Allowed CIDR blocks, one per line | |
github-service-hosts |
GitHub service hostnames to auto-allow on port 443 (one per line) | See defaults |
azure-infra-hosts |
Azure infrastructure hostnames to auto-allow on port 443 (one per line) | See defaults |
config-file |
Path to YAML/JSON config file for advanced rules | |
version |
CargoWall version to use | latest |
fail-on-unsupported |
Fail if eBPF not supported | false |
sudo-lockdown |
Enable sudo lockdown to prevent firewall bypass | false |
sudo-allow-commands |
Command paths to allow via sudo when locked, one per line | |
dns-upstream |
Upstream DNS server (auto-detected if not set) | auto-detect |
allow-existing-connections |
Allow pre-existing TCP connections at startup | true |
binary-path |
Path to a pre-built cargowall binary (skips download) | |
debug |
Enable debug logging | false |
audit-summary |
Generate audit summary in workflow summary | true |
github-token |
GitHub token for downloading the binary and fetching step timing in audit summary | ${{ github.token }} |
include-prerelease |
Include pre-release versions when resolving "latest" | false |
api-url |
CodeCargo API URL for audit upload and policy fetch (policy requires GitHub App) | https://app.codecargo.com |
offline |
Skip all CodeCargo API communication (audit upload and policy fetch) | false |
| Output | Description |
|---|---|
supported |
Whether eBPF firewall was successfully activated |
pid |
Process ID of the running cargowall instance |
- DNS Interception: CargoWall runs a DNS proxy that intercepts all DNS queries
- JIT Rule Updates: When a hostname is resolved, the resulting IPs are dynamically added to the firewall
- eBPF Filtering: A TC (Traffic Control) eBPF program filters egress traffic based on destination IP and port
- Docker Integration: Docker daemon is configured to use CargoWall's DNS proxy
flowchart LR
subgraph runner["GitHub Actions Runner"]
subgraph steps["Workflow Steps"]
S1["npm ci / docker build / etc."]
end
subgraph cw["CargoWall"]
DNS["DNS Proxy<br/>127.0.0.1:53"]
BPF["TC eBPF<br/>on eth0"]
Rules["Rule Engine"]
end
S1 -- "DNS query" --> DNS
DNS -- "resolve & update rules" --> Rules
Rules -- "allow/deny IPs" --> BPF
S1 -- "network traffic" --> BPF
end
BPF -- "allowed" --> Internet(("Internet"))
BPF -. "blocked" .-x Denied(("Denied"))
- Direct IP connections: Unless the IP is in an allowed CIDR
- Hostname connections: Unless the hostname matches an allowed pattern
- DNS tunneling: Queries for non-allowed domains are refused at the proxy
- Traffic to explicitly allowed hostnames and CIDR ranges
- Pre-existing TCP connections established before CargoWall starts (when
allow-existing-connections: true, the default)
CargoWall automatically allows certain traffic required for the runner and GitHub Actions to function.
Infrastructure (hardcoded):
| Traffic | Ports | Why |
|---|---|---|
| Localhost (127.0.0.0/8, ::1) | All | Internal communication |
| Azure IMDS (169.254.169.254) | 80 | Instance metadata on GitHub-hosted runners |
| DNS upstream server | 53 | Required for DNS resolution |
| systemd-resolved upstreams | 53, 80, 32526 | Runner DNS infrastructure |
| Docker bridge IP | 53 | DNS for containers |
ACTIONS_RUNTIME_URL host |
443 | GitHub Actions runtime |
ACTIONS_RESULTS_URL host |
443 | GitHub Actions results |
ACTIONS_CACHE_URL host |
443 | GitHub Actions cache |
ACTIONS_ID_TOKEN_REQUEST_URL host |
443 | GitHub Actions OIDC token requests |
| IPv6 multicast (ff00::/8) | All | Neighbor discovery, required for IPv6 |
| ICMPv6 | All | IPv6 neighbor discovery protocol |
GitHub service hostnames (configurable via github-service-hosts):
| Hostname | Ports | Why |
|---|---|---|
github.com |
443 | Git operations, API |
api.github.com |
443 | GitHub REST/GraphQL API |
githubapp.com |
443 | GitHub Apps infrastructure |
actions.githubusercontent.com |
443 | Actions artifact/cache/log services |
github.githubassets.com |
443 | GitHub static assets |
Azure infrastructure hostnames (configurable via azure-infra-hosts):
| Hostname | Ports | Why |
|---|---|---|
trafficmanager.net |
443 | Azure Traffic Manager (DNS routing) |
blob.core.windows.net |
443 | Azure Blob Storage (Actions artifacts) |
When sudo-lockdown: true, sudo is restricted so that subsequent workflow steps cannot disable the firewall. You control which commands are still allowed via sudo-allow-commands:
sudo-lockdown: true
sudo-allow-commands: |
/usr/bin/apt-get
/usr/bin/dockerWith this configuration, sudo apt-get install ... and sudo docker build ... will work, but attempts to run sudo iptables -F, sudo pkill cargowall, or sudo vim /etc/resolv.conf will be blocked.
Sudo lockdown also removes the current user from the docker group. This is because Docker group membership grants the ability to run containers with root-level access, which could be used to bypass the firewall.
| Runner Type | eBPF Support | Notes |
|---|---|---|
| GitHub-hosted (ubuntu-latest) | Yes | Full support with sudo |
| GitHub-hosted (ubuntu-22.04) | Yes | Full support with sudo |
| GitHub-hosted (ubuntu-24.04) | Yes | Full support with sudo |
| Self-hosted Linux | Yes | Requires kernel 5.x+ and CAP_BPF |
| GitHub-hosted macOS | No | macOS doesn't support eBPF |
| GitHub-hosted Windows | No | Windows doesn't support eBPF |
If you see warnings about eBPF not being supported:
- Ensure you're using a Linux runner (
ubuntu-latest) - The action runs with
sudowhich is required for eBPF - Check kernel version with
uname -r(need 5.x+)
If DNS queries are timing out:
- Check that
dns-upstreamis reachable - Verify the allowed hosts include your required domains
- Enable
debug: trueto see detailed logs
- Ensure Docker is running before the action
- CargoWall automatically configures Docker DNS
- Check
/etc/docker/daemon.jsonwas updated
Don't want to manage policies in workflow YAML? Sign up for the CodeCargo platform to create and assign CargoWall policies from a centralized dashboard — with hierarchical overrides at the org, repo, workflow, and job level. Just keep this action in your workflow and manage everything else from the UI.
- CargoWall documentation
- CargoWall repository — architecture, concepts, and how it works
- CodeCargo platform — centralized policy management and enterprise features
Apache 2.0 - See LICENSE for details.
This action is part of the CodeCargo project. Issues and PRs welcome!