Six independent security research teams broke into AI coding agents in the first half of 2026, and every attack targeted the same thing: the credentials the agent held. The credential crisis is documented - agents hold long-lived secrets, and those secrets are the attack surface. This post covers what you actually deploy to fix it.

The agentjacking research from Tenet Security puts the urgency in sharp focus. A fake Sentry error report can hijack a coding agent into running attacker code with the developer’s own privileges - 85% success rate across Claude Code, Cursor, and Codex, using nothing more than the 2,388 Sentry DSNs that are publicly visible in source code. The attacker’s goal in every case is the credentials the agent can reach.

The architectural answer is to remove those credentials from the agent’s reach entirely.

What a Credential-Holding Egress Gateway Actually Does

The core invariant: the agent never holds a real secret

The defining property of this pattern - as implemented by Deno’s open-source Claw Patrol (MIT, alpha) - is that the agent holds only a placeholder. The gateway substitutes the real credential on the wire as the request leaves. From Deno’s announcement: “The agent sends a placeholder like {{github_pat}} and the gateway swaps in the real token on the wire.”

A compromised agent process cannot leak keys it never held. This is the structural difference from every other control covered below. NetworkPolicy, sandboxes, and LLM gateways all assume the agent holds the secret and try to contain what the agent does with it. A credential-holding gateway removes the secret from the agent’s reach before the attack surface exists.

Tunnel in, terminate TLS, parse the protocol, inject the credential

Claw Patrol’s architecture defines five actors: Agent, Device, Transport, Gateway, and Upstream.

sequenceDiagram
    participant A as Agent
    participant D as Device Client
    participant T as WireGuard Tunnel
    participant G as Claw Patrol Gateway
    participant U as Upstream

    Note over A: holds {{github_pat}} only
    A->>D: Request with placeholder credential
    Note over D: per-process isolation (Linux netns / macOS NetworkExtension)
    D->>T: Captured outbound flow
    T->>G: Encrypted L3 packets
    Note over G: SNI peek on ClientHello, TLS terminate with minted P-256 leaf cert
    G->>G: Parse protocol (HTTP / Postgres / K8s)
    G->>G: Run CEL rules against wire-level facts
    G->>G: Credential plugin injects real token into header / startup message / auth slot
    G->>U: Request with real credential
    Note over U: Sees the gateway's address, never the agent
    U->>G: Response
    G->>A: Response (TLS re-wrapped)

The agent never sees the upstream’s real certificate, and the upstream never sees the agent’s address. The real credential lives entirely in the gateway.

For TLS flows on port 443, the gateway performs SNI peeking on the ClientHello. On a match, it terminates TLS with a P-256 leaf certificate minted on the fly (30-day validity, in-memory cache, signed by a CA the device trusted during onboarding). The persisted tunnel auth key is hidden from agent processes using an empty tmpfs overlay on Linux and system VPN preferences on macOS, so the agent cannot steal the tunnel credential either.

Protocol awareness: gating wire-level facts, not just IPs

This is where the pattern separates from every Kubernetes-native control. Claw Patrol’s protocol parsers expose per-family facts to a CEL rule engine. Documented protocol families:

  • http.* - parsed http.Request objects: method, path, headers, body
  • k8s.* - Kubernetes resource, verb, and namespace decoded from the API wire protocol
  • sql.* - table names from Postgres Query and Parse messages (sql.tables is documented in the config reference; the full sql.* fact set is not yet enumerated)
  • ClickHouse Native and ClickHouse HTTPS (hello packets)
  • SSH - channels and global requests

Rules are written in HCL with fields including endpoint, condition (CEL), verdict, and reason:

# Deny any agent attempt to read Kubernetes Secrets
rule "k8s-no-secrets" {
  endpoints = [kubernetes.deploy-dev, kubernetes.deploy-prod]
  condition = "k8s.resource == 'secrets'"
  verdict   = "deny"
}

# Block agent queries touching sensitive tables at the Postgres wire
rule "sql-no-sensitive-tables" {
  endpoints = [postgres.analytics]
  condition = "'payments' in sql.tables || 'user_pii' in sql.tables"
  verdict   = "deny"
  reason    = "Agent cannot query sensitive tables"
}

The k8s-no-secrets rule is adapted from the Claw Patrol README example (the plural endpoints field is valid per the config reference). The sql-no-sensitive-tables rule uses the documented sql.tables variable. The full sql.* fact set is not yet enumerated in the config reference, so verify CEL identifiers against it before deploying.

A NetworkPolicy configured to allow traffic only to the cluster API on port 443 cannot distinguish kubectl get pods from kubectl delete namespace prod. Claw Patrol can.

Allow, deny, and approval chains

Verdicts are not binary. For destructive-but-necessary actions, Claw Patrol supports approval chains that gate the action under human or model review rather than blocking it outright. Three documented approver plugins:

  • Dashboard approver - a built-in single-page app for live operator decisions
  • Human approver - Slack, Discord, or Telegram integration
  • LLM approver - synchronous LLM proctoring against an inline written policy
approver "deploy-proctor" {
  policy = <<-EOT
    Approve deployments to staging. Deny any deployment to prod
    that also changes a Secret or a NetworkPolicy in the same apply.
  EOT
}

Approvers can be chained - a model judges first, then a human confirms. The maintainer has noted that approval-timeout handling is still under active development.

The Alternatives, and Where Each One Stops

NetworkPolicy and Cilium egress: L3/L4, blind above the transport layer

Kubernetes NetworkPolicy operates at OSI layer 3/4. The official docs include a section titled “What you can’t do with network policies (at least, not yet),” framing the resource as controlling traffic at the IP address or port level. It cannot inspect HTTP paths, SQL verbs, or credentials.

Cilium’s egress gateway routes pods through a specific node and masquerades their outbound traffic with a predictable source IP (CiliumEgressGatewayPolicy). This is source-IP SNAT control - useful for firewall allow-listing by IP, but it does not inspect or gate protocol payloads. Cilium separately offers L7-aware network policy for HTTP, Kafka, and DNS via Envoy, but the egress gateway feature itself is IP-level and does not cover Postgres or the Kubernetes wire protocol.

NetworkPolicy is still essential in this architecture. Use it to force agent pod egress through the gateway’s IP and port. Let the gateway make the protocol-level decision.

LLM gateways (LiteLLM): HTTP to model endpoints only

LiteLLM and similar LLM gateways proxy HTTP calls in the OpenAI ChatCompletions format. They manage virtual keys, spend tracking, and per-model budgets. They govern the model call. They do not see the agent’s access to a Postgres database, the Kubernetes API, or an SSH server, and they do not inject the credentials the agent uses against those systems. The two tools solve different problems and coexist in the same stack.

Sandboxes (gVisor, Kata): process isolation without credential removal

gVisor is an application kernel that implements a Linux-like interface by intercepting syscalls via its Sentry and Gofer components. Kata Containers provide each workload a lightweight VM with a dedicated kernel. Both provide strong process isolation from the host.

The limitation for this threat model: the agent inside the sandbox still holds its credentials. A hijacked agent under gVisor or Kata can still use its database password or AWS access key - it just cannot escape to the host kernel while doing so. Run sandboxes for process isolation, gateways for credential and egress control. They are complementary, not interchangeable.

Kyverno admission control: governs deploy time, not live egress

Kyverno validates and mutates Kubernetes resources at admission time. It governs what gets deployed: image signatures, allowed registries, mandatory labels. It does not govern the agent’s live egress traffic or the credentials on the wire after the pod is running. It appears in the comparison because it is the most common admission-layer control in agent-focused Kubernetes architectures, but its scope ends at the pod boundary.

The control-to-threat matrix

graph LR
    subgraph wire["Protocol-Aware Wire Layer"]
        GW["Credential-Holding Gateway\nHTTP + SQL + K8s + SSH\nPrevents possession AND gates protocol facts"]
    end
    subgraph l7["L7 HTTP Only"]
        LITELLM["LLM Gateway (LiteLLM)\nHTTP/OpenAI format to model endpoints"]
    end
    subgraph l4["L3 / L4: IP Address + Port"]
        NP["NetworkPolicy"]
        CIL["Cilium Egress Gateway\n(source-IP SNAT)"]
    end
    subgraph ortho["Orthogonal Controls"]
        SB["Process Isolation\ngVisor | Kata Containers"]
        ADM["Deploy-time Admission\nKyverno"]
    end

    l4 --> l7
    l7 --> wire
    ortho --> wire

Each control operates at a different layer and stops a different subset of threats. Only the credential-holding gateway prevents credential possession, gates non-HTTP protocol operations, and acts at runtime.

ControlPrevent credential exfiltrationBlock destructive SQL verbBlock kubectl delete namespaceGate arbitrary HTTP egressCatch subprocess bypassRuntime control
Credential-holding egress gatewayYes - agent never holds itYes - sql.* ruleYes - k8s.* ruleYes - http.* ruleYes - wire-level captureYes
Kubernetes NetworkPolicyNoNoNoPartial - destination IP/port onlyNoYes
Cilium egress gatewayNoNoNoPartial - source-IP masquerade onlyNoYes
LLM gateway (LiteLLM)NoNoNoModel API HTTP onlyNoYes
gVisor / Kata sandboxNo - agent still holds itNoNoNoNoYes
Kyverno admission controlNoNoNoNoNoNo - deploy-time

Why MCP and HTTP Proxies Are Not Enough

A common architectural response: “Just give the agent a few MCP functions you control instead of raw credentials.” The argument is reasonable - scope what the agent can do by limiting the tools.

The gap is subprocesses. An agent told to query a database can call psql directly rather than going through an MCP tool wrapper. An agent told to apply a manifest can spawn kubectl. MCP and HTTP proxies sit above the process boundary; they do not intercept a subprocess that opens its own network connection.

A credential-holding egress gateway intercepts at the network layer. On Linux it uses per-process network namespaces; on macOS it uses the NetworkExtension framework. The subprocess is inside the same isolated network context as the parent agent process, so it hits the same gateway, the same rules, and the same credential injection path. MCP scoping is useful additional defense. It does not close the subprocess gap on its own.

Deploying the Pattern on Kubernetes

Claw Patrol’s current documentation is workstation-centric: the agent runs on an operator’s device and joins a gateway over a WireGuard or Tailscale tunnel. There is no official Kubernetes manifest or Helm chart at this time. The following maps the pattern onto in-cluster agents - treat it as an architecture reference, not a supported deployment, and check clawpatrol.dev for Kubernetes-specific documentation as the project matures.

graph LR
    subgraph agents["ai-agents namespace"]
        P1["Agent Pod A\n(placeholder only)"]
        P2["Agent Pod B\n(placeholder only)"]
        NP["NetworkPolicy\ndefault-deny egress\nallow → gateway only"]
    end

    subgraph gw["gateway namespace"]
        GW["Claw Patrol Gateway\nDeployment + Service\n(holds real credentials)"]
    end

    subgraph targets["Targets"]
        PG["In-cluster Postgres\n:5432"]
        K8S["Kubernetes API\n:6443"]
        EXT["External APIs"]
    end

    P1 -- WireGuard tunnel --> GW
    P2 -- WireGuard tunnel --> GW
    NP -. blocks direct egress .- PG
    NP -. blocks direct egress .- K8S
    GW --> PG
    GW --> K8S
    GW --> EXT

Architecture pattern for running a credential-holding gateway alongside Kubernetes agent workloads. The gateway namespace holds real credentials; the agent namespace holds only placeholders. NetworkPolicy prevents agents from reaching targets directly if the gateway tunnel fails.

The three CLI modes document the deployment shapes the project supports today:

# Run the gateway (holds credentials, evaluates rules)
clawpatrol gateway config.hcl

# Enroll a device into the gateway over a WireGuard/Tailscale tunnel
# (brings up WireGuard for the whole host)
clawpatrol join <gateway-url>

# Wrap a single agent's process tree in an ephemeral per-process tunnel
clawpatrol run claude

In a Kubernetes context, the clawpatrol run <agent-binary> pattern maps closest to a per-pod init: wrap the agent’s process tree in an isolated network context that routes through the gateway Service. Layer a default-deny egress NetworkPolicy on the agent namespace to ensure pods cannot reach Postgres or the Kubernetes API directly if the gateway tunnel fails to initialize:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: agents-default-deny-egress
  namespace: ai-agents
spec:
  podSelector: {}
  policyTypes: ["Egress"]
  egress: []   # deny all; add an allow rule scoped to the gateway Service ClusterIP

The NetworkPolicy enforces the egress path but makes no protocol-level decision. The gateway makes the decision.

Maturity caveats

Claw Patrol is MIT-licensed alpha software. Deno’s own description: “currently alpha software.” As of June 11, 2026, it is on v0.2.10 with 13 releases in quick succession. Approval-timeout handling is under active development. There is no official Kubernetes deployment guide. This is the project to understand and pilot in development environments now, not the control to put in front of production data stores unattended.

The architectural idea - the agent never holds a real credential, the gateway holds it and injects it on the wire - is the durable takeaway. Which implementation carries that idea into production is a maturity question that will resolve as the project and the category develop.

What to Do This Quarter

Inventory credential exposure. List every agent workload and the live credentials it holds. Focus on credentials with destructive scope: database passwords with write access, Kubernetes ServiceAccount tokens with broad RBAC, cloud access keys scoped to projects instead of specific resources.

Pilot a credential-holding gateway for one high-risk data store. Pick your most sensitive database or the most overprivileged agent ServiceAccount. Deploy Claw Patrol in your development environment, move the credential to the gateway, and replace it with a placeholder in the agent config. Start in watch-only mode (allow all, log everything) to see what the rule engine surfaces before you write deny rules.

Layer the controls you already run. Use NetworkPolicy to enforce the egress path to the gateway. Use Kyverno at deploy time to ensure only approved agent images reach the cluster. Use gVisor or Kata for strong process isolation. The credential-holding gateway adds a layer these controls do not cover; it does not replace them.

If a hijacked agent has nothing to exfiltrate and a protocol-aware deny rule blocks the destructive action, the attack surface collapses. That is the architectural argument for this pattern, and it holds regardless of which implementation matures first.

Frequently asked questions

How is a credential-holding egress gateway different from a Kubernetes NetworkPolicy?

A NetworkPolicy works at OSI layer 3/4 - it allows or blocks traffic by IP address and port, and the Kubernetes docs explicitly list inspecting application content as something you cannot do with it. A credential-holding egress gateway parses the actual protocol (HTTP, Postgres, the Kubernetes API), so it can deny a specific SQL verb or a delete on the secrets resource, and it injects the real credential on the wire so the agent never holds it. Use NetworkPolicy to force agent egress through the gateway, and the gateway to make the protocol-level decision.

Doesn’t an LLM gateway like LiteLLM already solve this?

No. An LLM gateway proxies HTTP calls to model endpoints in the OpenAI ChatCompletions format and manages virtual keys, spend, and budgets. It governs the model call. It does not see or gate the agent’s access to a Postgres database or the Kubernetes API, and it does not inject the credentials the agent uses against those systems. The two solve different problems and can coexist in the same stack.

If I run my agent in a gVisor or Kata sandbox, do I still need this?

Sandboxes and credential-holding gateways address different layers. gVisor (an application kernel that intercepts syscalls) and Kata (a lightweight VM per workload) isolate the agent process from the host. The agent inside the sandbox still holds whatever credentials it was given, so a hijacked agent can still use or leak them. A credential-holding gateway removes the secret from the agent entirely. Run both: sandbox for process isolation, gateway for credential and egress control.

Why can’t I just give the agent an MCP server with the few functions I allow?

Agents spawn subprocesses. An agent told to query a database can call psql directly and route around the MCP layer entirely. A credential-holding egress gateway intercepts at the network layer with per-process isolation (Linux network namespaces on Linux, NetworkExtension on macOS), so it catches the subprocess too. MCP scoping is useful defense-in-depth but does not close the subprocess gap on its own.

Is Claw Patrol production-ready?

Not yet. Deno describes it as “currently alpha software” (MIT, v0.2.10 as of June 11, 2026), and the maintainer has noted that approval-timeout handling is still under active development. Treat it as a pattern to understand and pilot on a single high-risk data store, not a drop-in production control. The architectural idea - the agent never holds a real credential - is the durable takeaway regardless of which implementation matures first.