OpenClaw + Pipelock Deployment Guide#
Pipelock sits between your AI agent and the OpenClaw gateway when the agent's MCP client is configured to use the Pipelock wrapper or generated MCP launcher contract. It scans that mediated MCP traffic for secret exfiltration, prompt injection, and tool poisoning. This guide covers deploying pipelock as a security layer for OpenClaw.
Why#
CVE-2026-25253 (CVSS 8.8) is a cross-site WebSocket hijacking attack against OpenClaw gateways. The attack chain:
- Victim clicks a malicious link
- Attacker's page opens a WebSocket to the victim's localhost gateway (no origin validation)
- Browser auto-sends the gateway auth token
- Attacker steals the token, connects to the gateway, disables sandbox and safety guardrails
- Attacker invokes
node.invokefor arbitrary code execution on the host
Pipelock blocks the post-compromise steps of this chain: tool policy blocks dangerous tool invocations, input scanning catches secret exfiltration in tool arguments, and response scanning detects injection in tool results. Pipelock does not currently perform handshake-level DLP on inbound WebSocket connections (that requires listener mode, which is planned but not yet implemented for WS upstreams).
Quick Start#
1. Install pipelock:
# Homebrew (macOS / Linux)
brew install luckyPipewrench/tap/pipelock
# Or download binary
curl -fsSL https://github.com/luckyPipewrench/pipelock/releases/latest/download/pipelock_linux_amd64.tar.gz | tar xz
sudo mv pipelock /usr/local/bin/
2. Generate a wrapped config:
Input must be a JSON file with a top-level mcpServers object.
# Wrap all MCP servers in your config with pipelock scanning
pipelock generate mcporter -i servers.json -o wrapped.json
# Or modify in-place (creates .bak backup)
pipelock generate mcporter -i servers.json --in-place --backup
3. Restart your agent. MCP traffic from that wrapped config now routes through pipelock.
Architecture#
┌─────────────────────────────────────────────────────────┐
│ Agent Host │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ │ │ │ │ │ │
│ │ Agent │───>│ Pipelock │───>│ OpenClaw Gateway │ │
│ │ │ │ MCP Proxy│ │ (ws/http) │ │
│ │ (secrets,│ │ │ │ │ │
│ │ no net) │ │ (no │ └──────────────────┘ │
│ │ │ │ secrets, │ │ │
│ └──────────┘ │ scans │ │ │
│ │ traffic)│ ▼ │
│ └──────────┘ ┌──────────────┐ │
│ │ Internet │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
In an enforced deployment, the agent has secrets but no direct network access. Pipelock has no agent secrets but full network access. Deployment controls such as Docker networking, host containment, firewall rules, or K8s NetworkPolicy enforce this boundary. This capability separation prevents a compromised agent from exfiltrating secrets directly.
Two Protection Layers#
Layer 1: MCP Proxy (tool calls and responses)#
Wraps the OpenClaw gateway connection with bidirectional scanning:
- Response scanning detects prompt injection in tool results
- Input scanning catches DLP violations and injection in tool arguments
- Tool scanning detects poisoned tool descriptions and rug-pull drift
- Tool policy blocks dangerous tool invocations (shell commands, file access)
- Chain detection catches suspicious tool call sequences (read-then-exfil patterns)
- Session binding pins the tool inventory per session to prevent tool swapping
Layer 2: HTTP Proxy (fetch and forward)#
When the agent makes outbound HTTP requests through pipelock's fetch proxy:
- 11-layer URL scanning (CRLF, path traversal, blocklist, DLP, SSRF, rate limiting, entropy checks)
- Response injection detection on fetched content
- Data budget tracking per domain
Configuration#
Stdio-to-WebSocket (most common)#
Your agent talks to pipelock over stdin/stdout. Pipelock connects to the OpenClaw gateway over WebSocket.
{
"mcpServers": {
"openclaw": {
"command": "pipelock",
"args": [
"mcp", "proxy",
"--config", "/path/to/pipelock.yaml",
"--env", "OPENCLAW_GATEWAY_URL",
"--env", "OPENCLAW_GATEWAY_TOKEN",
"--upstream", "ws://localhost:3000/mcp"
],
"env": {
"OPENCLAW_GATEWAY_URL": "ws://localhost:3000",
"OPENCLAW_GATEWAY_TOKEN": "your-token-here"
}
}
}
}
Stdio-to-HTTP#
If your OpenClaw gateway exposes an HTTP MCP endpoint:
{
"mcpServers": {
"openclaw": {
"command": "pipelock",
"args": [
"mcp", "proxy",
"--config", "/path/to/pipelock.yaml",
"--upstream", "http://localhost:3000/mcp"
]
}
}
}
Using generate mcporter#
Instead of manually editing configs, use the generator:
# Preview what will change (outputs to stdout)
pipelock generate mcporter -i mcporter.json
# Write to a new file
pipelock generate mcporter -i mcporter.json -o wrapped.json
# Modify in-place with backup
pipelock generate mcporter -i mcporter.json --in-place --backup
# Custom pipelock binary path and config
pipelock generate mcporter -i mcporter.json \
--pipelock-bin /usr/local/bin/pipelock \
--config /etc/pipelock/pipelock.yaml
The generator is idempotent. Running it twice produces identical output. Servers already wrapped with pipelock are detected and skipped.
Kubernetes Sidecar Deployment#
For enforced cluster deployments, generate a companion-proxy topology and point it at the OpenClaw MCP endpoint:
pipelock init sidecar \
--inject-spec agent-deployment.yaml \
--mcp-upstream http://openclaw-gateway:3000/mcp \
--mcp-server-name openclaw \
--output enforced.yaml
kubectl apply -f enforced.yaml
The generated agent workload gets HTTPS_PROXY and HTTP_PROXY for HTTP egress, plus two MCP launcher inputs:
PIPELOCK_MCP_PROXY_URL=http://<pipelock-service>:8889PIPELOCK_MCP_CONFIG=/etc/pipelock/mcp/mcp.json
The mounted mcp.json contains an mcpServers.openclaw entry whose URL points at Pipelock's MCP listener. Configure your agent launcher to read PIPELOCK_MCP_CONFIG, or configure the MCP client directly from PIPELOCK_MCP_PROXY_URL. The generated NetworkPolicy limits the agent pod to DNS plus the Pipelock HTTP and MCP proxy ports, so direct egress to the OpenClaw gateway is outside the generated agent boundary.
Same-pod sidecar wiring is still useful for local prototypes, but it relies on the agent honoring proxy settings and is not the generated enforced topology:
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent
spec:
template:
spec:
initContainers:
- name: pipelock-init
image: ghcr.io/luckypipewrench/pipelock-init:latest
command: ["cp", "/pipelock", "/shared-bin/pipelock"]
volumeMounts:
- name: shared-bin
mountPath: /shared-bin
containers:
- name: agent
image: your-agent:latest
env:
- name: HTTPS_PROXY
value: "http://localhost:8888"
volumeMounts:
- name: shared-bin
mountPath: /usr/local/bin/pipelock
subPath: pipelock
- name: config
mountPath: /etc/pipelock
readOnly: true
- name: pipelock
image: ghcr.io/luckypipewrench/pipelock:latest
args: ["run", "--listen", "0.0.0.0:8888"]
ports:
- containerPort: 8888
volumeMounts:
- name: config
mountPath: /etc/pipelock
readOnly: true
volumes:
- name: config
configMap:
name: pipelock-config
- name: shared-bin
emptyDir: {}
If you keep a same-pod prototype, do not treat a pod-level NetworkPolicy as a container-level wall between containers in that same pod. Kubernetes NetworkPolicy selects pods, not individual containers, so it cannot stop one container from reaching destinations another container in the same pod can reach. For enforced cluster isolation, prefer the generated companion-proxy topology above, where the agent pod and Pipelock service are separate policy subjects.
For a separate-agent-pod topology, a NetworkPolicy should restrict the agent pod's egress to DNS and the Pipelock Service:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: agent-egress
spec:
podSelector:
matchLabels:
app: agent
policyTypes:
- Egress
egress:
# Allow DNS resolution.
- to:
- namespaceSelector: {}
ports:
- port: 53
protocol: UDP
# Allow traffic only to pods selected as the Pipelock proxy Service backend.
- to:
- podSelector:
matchLabels:
app: pipelock
ports:
- port: 8888
What Pipelock Mitigates#
Mapped to the CVE-2026-25253 attack chain:
| Attack Step | Pipelock Defense | Layer |
|---|---|---|
| Token theft via WS handshake | Not yet mitigated (requires WS listener mode, planned) | -- |
| Sandbox disable via tool call | Tool policy blocks dangerous tool invocations | MCP proxy |
RCE via node.invoke | Tool policy deny rules for shell/exec tools | MCP proxy |
| Data exfiltration via tool args | Input scanning catches secrets in outbound calls | MCP proxy |
| Prompt injection in tool results | Response scanning detects injection attempts | MCP proxy |
| Read-then-exfil tool sequences | Chain detection catches multi-step patterns | MCP proxy |
| Outbound HTTP exfiltration | 11-layer URL scanning, DLP on request URLs | HTTP proxy |
Pipelock does not patch the CVE itself (that requires OpenClaw origin validation). It adds defense-in-depth by scanning the mediated traffic between agent and gateway, catching exploitation attempts at multiple points in the attack chain.
TLS Interception#
When using pipelock as an HTTP forward proxy (HTTPS_PROXY), CONNECT tunnels
are opaque by default: pipelock only sees the hostname, not the request body or
response content. Enabling TLS interception closes this gap by performing a MITM
on HTTPS connections, giving you full DLP on request bodies and response
injection detection through CONNECT tunnels.
To enable it:
- Generate a CA and enable TLS interception (see the TLS Interception Guide)
- Trust the CA in your agent's runtime:
# Node.js agents
export NODE_EXTRA_CA_CERTS=~/.pipelock/ca.pem
# Python agents
export SSL_CERT_FILE=~/.pipelock/ca.pem
MCP proxy mode (stdio wrapping and --upstream) does not require TLS
interception. It scans traffic directly without certificates.
Troubleshooting#
Connection refused to upstream#
Check that the OpenClaw gateway is running and accessible at the configured URL:
# For WebSocket upstreams
wscat -c ws://localhost:3000/mcp
# For HTTP upstreams
curl http://localhost:3000/mcp
DLP false positives#
If pipelock blocks legitimate traffic containing strings that match DLP patterns, add suppression rules to your config:
suppress:
- rule: "dlp_*"
path: "*.example.com"
reason: "Known safe endpoint"
Tool policy blocks#
If pipelock blocks a tool invocation your agent needs:
mcp_tool_policy:
enabled: true
action: warn # Change from "block" to "warn" for debugging
rules:
- name: "allow my tool"
tool_pattern: "^your_tool_name$"
action: warn
Checking what pipelock scanned#
Enable verbose logging by including allowed (non-blocked) events:
logging:
include_allowed: true
include_blocked: true
Or check the structured audit log for specific events.
See Also#
- Configuration Reference for all pipelock config fields
- Deployment Recipes for Docker Compose, Kubernetes, iptables, and macOS PF examples
- Transport Modes for a comparison of all proxy modes and their scanning capabilities
- Attacks Blocked for real-world attack examples and how pipelock handles them
- Finding Suppression for managing DLP false positives
- Tool Policy Spec for the full tool policy rule format