# How the Agent Workflow Firewall (AWF) Integration Provides Egress Control in GitHub Actions

> Learn how the Agent Workflow Firewall AWF integration provides egress control in GitHub Actions by sandboxing AI engine commands and enforcing network restrictions on domains.

- Repository: [GitHub/gh-aw](https://github.com/github/gh-aw)
- Tags: internals
- Published: 2026-02-16

---

**The Agent Workflow Firewall (AWF) integration provides egress control by wrapping AI engine commands in a sandboxed container that enforces network restrictions through command-line arguments specifying allowed and blocked domains.**

The `github/gh-aw` repository implements the Agent Workflow Firewall (AWF) to isolate AI-driven workflows inside GitHub Actions. By centralizing egress policy generation in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go), the integration transforms declarative network permissions into concrete firewall rules that restrict outbound traffic at runtime.

## Architectural Overview of AWF Egress Control

The AWF operates as a sandbox wrapper around every AI engine command executed by `gh-aw`. When a workflow lacks explicit sandbox configuration, the system automatically applies defaults that designate the AWF as the isolation mechanism.

### Sandbox Defaults and Configuration

In [`pkg/workflow/sandbox.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/sandbox.go), the `applySandboxDefaults` function ensures that workflows without custom sandbox settings receive an `agent: awf` configuration. This default assignment guarantees that every engine execution receives network isolation unless explicitly overridden.

The default AWF command itself is defined in [`pkg/constants/constants.go`](https://github.com/github/gh-aw/blob/main/pkg/constants/constants.go) as `sudo -E awf`, though operators may override this via the `AgentSandboxConfig.Command` field.

### Command Resolution and Prefix Generation

The `GetAWFCommandPrefix` function in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go) resolves the final command prefix. It checks for custom sandbox commands; if none exist, it falls back to the constant `AWFDefaultCommand`. This prefix forms the base of the eventual firewall invocation.

## Building the AWF Command for Network Restrictions

Egress control materializes through the `BuildAWFArgs` function, which translates workflow-level network permissions into AWF-specific command-line flags.

### Domain Allowlisting and Blocklisting

The function constructs three critical argument categories:

- **`--allow-domains`**: Populated from the workflow front-matter `network.allowed` field. This comma-separated list explicitly permits outbound connections to specified hosts. An empty list results in **zero egress**, effectively creating an air-gapped environment.
- **`--block-domains`**: Derived from `NetworkPermissions.Blocked`. These domains are explicitly denied regardless of other permissions. The validation layer rejects wildcard entries in strict mode to prevent overly broad blocking.
- **`--mount`**: Custom mount points from the sandbox configuration that expose necessary filesystem resources without compromising network isolation.

### Additional Security Flags

Beyond domain controls, `BuildAWFArgs` appends several security-hardening parameters:

- **`--enable-host-access`**: Conditionally added when MCP (Model Context Protocol) gateway containers are present, allowing the firewall to reach host services required for MCP functionality.
- **`--image-tag`**: Pins the AWF container image to a specific version defined in [`pkg/constants/constants.go`](https://github.com/github/gh-aw/blob/main/pkg/constants/constants.go), ensuring reproducible rule enforcement.
- **`--enable-api-proxy`**: Activates when API proxying is required for specific engine interactions.
- **SSL/TLS options**: Additional flags handle certificate bumping and TLS inspection when enterprise TLS interception is configured.

## Code Example: Generating an AWF-Wrapped Engine Command

The following Go code demonstrates how `gh-aw` assembles the final AWF command using the helper functions in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go):

```go
import (
    "github.com/github/gh-aw/pkg/workflow"
    "github.com/github/gh-aw/pkg/constants"
)

func example() string {
    // Assume we already have a parsed WorkflowData (populated by the compiler)
    wfData := &workflow.WorkflowData{ /* …filled by gh‑aw… */ }

    cfg := workflow.AWFCommandConfig{
        EngineName:    "copilot",
        EngineCommand: "copilot chat --model gpt-4o-mini",
        LogFile:       "/tmp/gh-aw/engine.log",
        WorkflowData:  wfData,
        UsesTTY:       false,
        UsesAPIProxy:  true,
        AllowedDomains: "api.github.com,registry.ghcr.io",
        PathSetup:     "export PATH=$HOME/.local/bin:$PATH",
    }

    // Produces the full script that will be placed in a GitHub‑Actions step
    return workflow.BuildAWFCommand(cfg)
}

```

This invocation produces a shell script similar to:

```bash
set -o pipefail
sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" \
  --allow-domains api.github.com,registry.ghcr.io \
  --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs \
  --enable-host-access --image-tag v0.18.0 --skip-pull --enable-api-proxy \
  -- /bin/bash -c 'copilot chat --model gpt-4o-mini' 2>&1 | tee -a /tmp/gh-aw/engine.log

```

Only the domains explicitly listed in `--allow-domains` are reachable from within the engine container.

## Execution Flow and Runtime Enforcement

When GitHub Actions executes the generated step, the AWF container initializes with a restricted network namespace. The enforcement mechanism operates as follows:

1. **Default Deny**: Without explicit `--allow-domains`, the firewall implements a default-deny policy, preventing all outbound connections.
2. **Selective Permits**: Domains listed in `--allow-domains` are resolved and added to the container's egress whitelist.
3. **Explicit Blocks**: Entries in `--block-domains` override any other permissions, ensuring specific hosts remain unreachable.
4. **Host Access Gateway**: When `--enable-host-access` is present, the firewall creates a controlled bridge to host-local MCP services without exposing the broader network.

This architecture ensures that AI engine workflows operate with the principle of least privilege, contacting only the external resources explicitly authorized by the workflow definition.

## Summary

- The **Agent Workflow Firewall (AWF)** integration in `github/gh-aw` provides deterministic egress control by wrapping AI engine commands in a sandboxed container.
- Network policies are defined in workflow front-matter and compiled into AWF command-line arguments by functions in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go).
- **Domain allowlisting** (`--allow-domains`) and **blocklisting** (`--block-domains`) provide granular control, with an empty allowlist resulting in complete network isolation.
- Additional flags like `--enable-host-access` and `--image-tag` harden the execution environment while maintaining necessary functionality for MCP gateways and version consistency.

## Frequently Asked Questions

### What happens if no allowed domains are specified in the AWF configuration?

If the workflow front-matter does not specify any domains in `network.allowed`, the `BuildAWFArgs` function in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go) passes an empty string to the `--allow-domains` flag. AWF interprets this as a default-deny policy, blocking all outbound network connections and creating an air-gapped environment for the AI engine.

### How does AWF handle wildcard domains in blocklists?

The AWF integration explicitly forbids wildcard entries in the blocklist when strict-mode validation is enabled. The validation logic in the workflow compiler rejects patterns that could match overly broad domain sets, ensuring that `--block-domains` contains only specific, explicit hostnames that the AWF container will definitively reject.

### Can I use a custom AWF binary instead of the default sudo -E awf?

Yes. While [`pkg/constants/constants.go`](https://github.com/github/gh-aw/blob/main/pkg/constants/constants.go) defines `AWFDefaultCommand` as `sudo -E awf`, you can override this by specifying a custom command in the `AgentSandboxConfig.Command` field. The `GetAWFCommandPrefix` function in [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go) checks for this override and uses the custom path when present, falling back to the default only when no alternative is specified.

### What is the purpose of the --enable-host-access flag in AWF?

The `--enable-host-access` flag is conditionally added by `BuildAWFArgs` when the workflow configuration includes MCP (Model Context Protocol) gateway containers. This flag creates a controlled network bridge that allows the AWF container to reach host-local services required for MCP functionality without exposing the broader external network, maintaining the principle of least privilege while enabling necessary integrations.