Skip to content

Releases: nnemirovsky/sluice

v0.14.0

08 May 13:31
399807c

Choose a tag to compare

New Features

  • CIDR rule destinations: rules whose destination contains a / are now interpreted as CIDR (e.g. 192.168.0.0/16, 2001:db8::/32) and matched via IP containment instead of being treated as literal glob patterns (#39)
  • HTTP Host header peeking on port 80 / 8080: SOCKS5 CONNECT requests that arrive with a bare IP and a non-Allow / non-Deny verdict now defer policy evaluation, peek the request's Host header, and re-evaluate against the recovered hostname. Mirrors the existing TLS SNI peek path. Eliminates the need for one approval rule per IP behind a hostname rule (e.g. tailscale's DERP probes hitting dozens of derp[N].tailscale.com IPs) (#39)

Security hardening for the new HTTP Host path

  • Spoofing guard verifies the recovered Host actually binds to the destination IP via the DNS interceptor's reverse cache or a forward DNS lookup. A claim like Host: api.openai.com to an arbitrary IP is rejected before the verdict is upgraded (#39)
  • Peek failure on a deferred port-80 connection attaches a per-request policy checker bound to the IP destination so the broker still gets to ask, instead of silently upgrading the original Ask verdict to an allow (#39)
  • HTTP-host deferral is gated on broker presence so Ask-without-broker continues to collapse to Deny via the IP-based path before SOCKS5 success goes out, avoiding success-then-reset on the client side (#39)

v0.13.2

07 May 11:02
61f4c00

Choose a tag to compare

Bug Fixes

  • env-file ownership: chown the agent env file back to the runtime user after docker exec writes it as root, so hermes claw migrate and other agent-side writes keep working (#38)
  • panic recovery in MITM response and stream paths: deferred recovers in Response and StreamResponseModifier log the stack and fall back to safe defaults so an OAuth handler panic no longer abandons the response body and triggers a JSONDecodeError in the agent (#38)
  • OAuth-vs-static header dispatch: header bindings on OAuth credentials no longer substitute the full JSON envelope into the request header. A new metadata-driven helper (extractInjectableSecret) reads from OAuthIndex to extract just access_token for OAuth credentials and pass static credentials through unchanged. Mirrored into the QUIC proxy so HTTP/3 follows the same dispatch as HTTP/1 and HTTP/2 (#38)
  • stream OAuth body leak guard: when a panic fires after io.ReadAll but before swapOAuthTokens returns, the recover no longer hands the agent the raw upstream bytes (which would contain real access and refresh tokens). The fallback is now http.NoBody until a successful swap produces a phantom-only buffer (#38)
  • nil-input guard ordering: the StreamResponseModifier nil-input check now runs before the flow-nil early return, so a call with both f == nil and in == nil returns http.NoBody instead of a nil reader (#38)

v0.13.1

07 May 07:59
d27b05e

Choose a tag to compare

Bug Fixes

Hermes deployment fixes that emerged from running v0.13.0 in production. All six are real correctness or compatibility issues, not just polish.

  • OAuth response handler: now decompresses gzip/br/deflate before parsing the token JSON, and is wrapped in a deferred recover with snapshot/rollback so a malformed body cannot panic the proxy or leave a half-rewritten response with stripped encoding headers. Reproduced live against auth.openai.com which returns gzip by default.
  • Env-file marker block: sluice now writes phantom tokens into a fenced BEGIN sluice-managed / END sluice-managed block and replaces only that block on each call. Foreign keys (set by hermes claw migrate, the agent's own auth flow, or an operator) are preserved across both incremental updates and full reconciliation runs. Values are written single-quoted so the file is safe under both shell source and dotenv parsing.
  • MCP gateway always mounts: the /mcp endpoint used to mount only when a sluice MCP upstream was registered. Agents that registered sluice as an MCP server (the documented setup) hit a 404 before the operator could add the first upstream. Now the gateway always starts; with zero upstreams it exposes an empty tool list.
  • HermesProfile WireMCPCmd uses the bundled venv: a sh wrapper activates /opt/hermes/.venv when present so PyYAML is on the import path inside the official Hermes image. Native installs without the venv keep working via the system python3.
  • SSH proxy exit-status race: sshHandleChannel previously called srcChan.CloseWrite from the upstream→agent data-copy goroutine the moment it saw EOF, racing the request-forwarder writing exit-status on the same channel. Fix holds the agent-side stdout EOF until every upstream→agent goroutine has drained, then issues CloseWrite followed by Close. Stdin direction is unchanged so upstream commands like cat still terminate correctly.
  • Configurable Telegram agent label: approval messages used to read "OpenClaw wants to connect to..." regardless of the active profile. New SetAgentDisplayName is wired from the --agent flag at startup. Hermes deployments now read "Hermes wants to connect to...". The display name is HTML-escaped at render time.

Deploy files

The repo's compose.yml, compose.dev.yml, and Caddyfile switch to the Hermes stack as the supported deployment. A new bootstrap.sh runs hermes claw migrate against an existing OpenClaw home volume one time, then patches mcp_servers.sluice.url into ~/.hermes/config.yaml. Caddy cert paths moved off provider-specific /etc/cloudflare/... to standard FHS /etc/ssl/certs/agent.pem + /etc/ssl/private/agent.key.

Operators on OpenClaw who want to keep the v0.12.x deployment shape can pin to ghcr.io/nnemirovsky/sluice:0.12 and use the compose / Caddyfile from any v0.12.x tag.

#37 @nnemirovsky

v0.13.0

07 May 04:23
9cd1a3e

Choose a tag to compare

New Features

Sluice now supports nousresearch/hermes-agent as a first-class target alongside OpenClaw. The container managers (Docker, Apple Container, tart) consume an AgentProfile that captures the env file path, secrets-reload mechanism, and MCP wiring command for one agent runtime. Select with --agent <name> (or SLUICE_AGENT_PROFILE); default is openclaw so existing setups are unaffected.

The Hermes profile writes phantom tokens to ~/.hermes/.env and patches mcp_servers.<name>.url in ~/.hermes/config.yaml via an embedded python3 + pyyaml script. Hermes has no documented in-place secret reload, so new env values take effect on the next agent message; for MCP changes, run /reload-mcp from the Hermes chat session or restart the container once after first wire-up.

Adding a third agent profile is a single edit to internal/container/agent_profile.go.

v0.12.0

20 Apr 11:35
4943433

Choose a tag to compare

New Features

Improvements

v0.11.0

14 Apr 13:04
7e043b8

Choose a tag to compare

New Features

  • add ExecInspector for trampoline and dangerous pattern detection in MCP tool arguments
  • add MITM response DLP scanning for HTTPS response bodies and headers
  • add sluice policy add redact CLI subcommand and /policy redact Telegram command

Details

  • ExecInspector (internal/mcp/exec_inspect.go) detects trampoline patterns (bash -c, python -c), dangerous commands (rm -rf /, chmod 0?[0-7]?777, curl | sh, fork bombs), env overrides (GIT_SSH_COMMAND, LD_PRELOAD, DYLD_INSERT_LIBRARIES), and shell metacharacters. Field-scoped scanning with recursion into nested maps (wrapped schemas), case-insensitive slot matching, and split-argv reconstruction across command + args. Default tool-name patterns anchored to the MCP __ separator to avoid false positives on tools like shellcheck.
  • Response DLP (internal/proxy/response_dlp.go) runs per-response regex scan of buffered response bodies and headers using InspectRedactRule rows from the policy store. Supports gzip, br, deflate (zlib-wrapped per RFC 9110), and zstd. Handles up to 2 stacked Content-Encoding layers. Bounded decompression via io.LimitReader capped at maxProxyBody (16 MiB). Distinct from phantom-token stripping, which protects outbound requests. This protects the agent from seeing real credentials leaked by upstreams in responses.
  • Rule management across all channels. New CLI subcommand sluice policy add redact <pattern> --replacement "[REDACTED_X]" and Telegram /policy redact <pattern> [replacement]. HTTP API already supported this via POST /api/rules with verdict: "redact". TOML import/export continues to work via [[redact]] blocks. SIGHUP reloads rebuild the engine and atomically swap via atomic.Pointer.
  • Audit redaction. exec_block audit events include only the attack category (trampoline, dangerous_cmd, env_override, metachar), never the raw matched content, so audit logs cannot leak credentials embedded in blocked payloads.

Known limitation

Responses with Content-Type: text/event-stream or bodies exceeding go-mitmproxy's StreamLargeBodies (5 MiB) enter streaming mode, which skips the buffered DLP scan. A one-per-connection WARNING log fires when DLP rules are configured but the response streams. Stream-aware DLP is listed as Future work.

PR: #33

v0.10.2

13 Apr 06:24
6f673c4

Choose a tag to compare

Fixes

  • Stop Telegram from auto-linking destinations in /policy show, /policy allow, /policy deny, and approval prompts (#32). Destinations, host:port, and request URLs now render as inline monospace.

v0.10.1

13 Apr 05:40
b519e2c

Choose a tag to compare

Fixes

  • Telegram /policy show now surfaces protocols, replacement, name, and source (#31)
  • CLI sluice policy list now shows replacement for redact rules (#31)

v0.10.0

13 Apr 02:44
421579e

Choose a tag to compare

Highlights

QUIC/HTTP3 now works end-to-end through the full tun2proxy -> sluice -> upstream pipeline. UDP and QUIC policy evaluation is now unified with TCP semantics (unscoped rules match all transports, engine default verdict applies). Broader e2e test coverage across WebSocket, gRPC, QUIC/HTTP3, DNS, and IMAP/SMTP.

New Features

  • QUIC SNI extraction from Initial packets via RFC 9001 decryption (ExtractQUICSNI, supports QUIC v1 and v2)
  • CRYPTO data accumulation across fragmented QUIC Initial packets so SNI can be reassembled from large ClientHellos
  • Broker request deduplication with bounded per-session packet buffer (prevents duplicate Telegram prompts during approval wait)
  • sluice policy add --protocols flag for creating protocol-scoped rules
  • WebSocket handshake credential injection (requires the go-mitmproxy fork fixes)
  • Comprehensive e2e tests for WebSocket, gRPC, QUIC/HTTP3, DNS, and IMAP/SMTP

Bug Fixes

  • QUIC falls back to the engine's configured default verdict instead of hardcoded Deny
  • Unscoped policy rules now apply to UDP/QUIC (DNS keeps its own evaluation path)
  • Shared-IP session key collision: pending approvals now keyed by hostname, preventing CDN-fronted destinations from colliding
  • Race between session publish and pending entry delete closed atomically
  • httptest servers use IPv4-only listeners to avoid IPv6 bind failures in sandboxed environments
  • SSH jump host test flakiness addressed

Upstream PRs

  • lqqyt2423/go-mitmproxy#100: forward modified request headers on WebSocket upgrade (paired with existing PR firing Requestheaders for WS)

v0.9.0

12 Apr 10:15
085fd23

Choose a tag to compare

Per-request policy, go-mitmproxy migration, QUIC Ask

- Per-request HTTP policy: "Allow Once" means one HTTP request, not one TCP connection
- Replaced goproxy with go-mitmproxy for HTTP/2 per-stream interception
- gRPC-over-HTTP/2 now has per-request policy (each stream triggers approval)
- QUIC/HTTP3 per-request Ask verdicts via EvaluateQUICDetailed
- Single Telegram message per request (combined destination + method + path)
- WebSocket approval via go-mitmproxy fork (Requestheaders fires before upgrade)
- E2E tests with configurable webhook approval channel
- Protocol-aware deferred ask for non-TLS protocols (SSH, SMTP, plain TCP)