In Chapter 3: Safe Outputs System, we acted like a bank manager, ensuring that the AI agent couldn't rob the vault (your repository) by strictly controlling its Write Access.
But what if the spy isn't trying to steal money, but trying to leak secrets? Or what if the agent accidentally downloads a virus from the internet?
This brings us to the Isolation Layer.
Imagine a scientist working with a dangerous virus. They don't work at a kitchen table. They work inside a Bio-Safety Cabinet:
In GitHub Agentic Workflows, the AI Agent is the scientist:
evil-server.com. It can only talk to specific, trusted domains you list on the door.
Standard GitHub Actions runners have unrestricted internet access. If you run npm install and a malicious package steals your GITHUB_TOKEN, it sends it to a hacker's server immediately.
Our Isolation Layer (Agent Workflow Firewall - AWF) prevents this by blocking all outgoing network traffic by default, only allowing what is necessary.
Let's look at how to set this up in your Markdown workflow.
You define the rules in the network section of your workflow file.
---
name: Secure Fixer
network:
firewall: true
allowed:
- defaults # GitHub APIs, etc.
- python # PyPI (to download packages)
- "api.google.com" # A specific trusted domain
---
# Instructions
Write a script that queries Google API.
When the agent tries to run code:
requests.get("https://api.google.com") -> ALLOWED.requests.get("https://hacker.site") -> BLOCKED (Connection Refused).This happens transparently. The agent doesn't know it's in a cage until it hits the bars.
How do we technically achieve this isolation on a GitHub Runner? We use a sidecar container proxy.
The system uses iptables (Linux networking rules) to force all traffic from the Agent container to go through the Proxy container. The Agent cannot bypass this.
The Workflow Compiler (from Chapter 1) is responsible for checking if the firewall should be on.
In pkg/workflow/firewall.go, the system decides whether to deploy the isolation layer:
// isFirewallEnabled determines if we need to lock the doors
func isFirewallEnabled(workflowData *WorkflowData) bool {
// 1. Did the user explicitly disable it in the sandbox settings?
if isFirewallDisabledBySandboxAgent(workflowData) {
return false
}
// 2. Did the user explicitly ask for it?
if workflowData.NetworkPermissions.Firewall.Enabled {
return true
}
// 3. Default: If using a Sandbox, the firewall is ON.
return isSandboxEnabled(workflowData)
}
Once enabled, we need to translate your simple list (python, node) into technical rules for the proxy. We also handle advanced features like "SSL Bump" (which allows the proxy to inspect HTTPS URLs, not just domain names).
// From pkg/workflow/firewall.go
func getSSLBumpArgs(config *FirewallConfig) []string {
if config == nil || !config.SSLBump {
return nil
}
// Enable deep inspection of encrypted traffic
args := []string{"--ssl-bump"}
// Add specific URL paths to the allow list
if len(config.AllowURLs) > 0 {
list := strings.Join(config.AllowURLs, ",")
args = append(args, "--allow-urls", list)
}
return args
}
SSLBump, the firewall acts like a "Man in the Middle" (a good one). It decrypts the traffic locally to check the full URL (e.g., allow github.com/my-org but block github.com/other-org), then re-encrypts it.Network is only half the battle. We also need to restrict the filesystem.
The Agentic Engine (from Chapter 2) runs inside a container. By default, it can:
/etc, /usr/bin of the host).
In pkg/workflow/sandbox.go, we manage the configuration for this container.
// SandboxConfig defines the environment structure
type SandboxConfig struct {
// Configuration for the Agent's container
Agent *AgentSandboxConfig `yaml:"agent,omitempty"`
// Configuration for MCP Servers (covered in Chapter 6)
MCP *MCPGatewayConfig `yaml:"mcp,omitempty"`
}
When the system boots up, it applies defaults to ensure you are protected even if you forget to configure it.
// applySandboxDefaults ensures safety is on by default
func applySandboxDefaults(config *SandboxConfig) *SandboxConfig {
// If no config exists, create a default "AWF" (Firewall) sandbox
if config == nil {
return &SandboxConfig{
Agent: &AgentSandboxConfig{ Type: SandboxTypeAWF },
}
}
return config
}
You might notice code referencing "SRT" (Sandbox Runtime). This was an older system. The project includes logic to automatically migrate users to the new, more secure AWF system.
func migrateSRTToAWF(config *SandboxConfig) *SandboxConfig {
// If the user asks for "srt", give them "awf" instead
if config.Type == "srt" {
sandboxLog.Printf("Migrating legacy sandbox to AWF")
config.Type = SandboxTypeAWF
}
return config
}
The Isolation Layer is the invisible shield of the GitHub Agentic Workflows.
By combining Read-Only Permissions (Chapter 3) with Network Isolation (Chapter 4), we have created a very secure environment. The agent is locked in a room, unable to break out, unable to call home, and unable to overwrite the master records.
But even within a locked room, an agent might write code that looks safe but contains a hidden vulnerability. How do we spot that?
Next Chapter: Threat Detection Layer
Generated by Code IQ