Skip to content

feat(proxy,mcp): tool argument and network response DLP hardening#33

Merged
nnemirovsky merged 10 commits intomainfrom
tool-network-dlp-hardening
Apr 14, 2026
Merged

feat(proxy,mcp): tool argument and network response DLP hardening#33
nnemirovsky merged 10 commits intomainfrom
tool-network-dlp-hardening

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

Summary

Two new governance layers for data loss prevention.

  1. ExecInspector (MCP gateway): structural inspection of tool arguments for exec-like tools. Detects trampolines (bash -c, python -c), dangerous commands (rm -rf /, chmod 777, curl | sh, fork bombs), env overrides (GIT_SSH_COMMAND, LD_PRELOAD), and shell metacharacters. Runs between ContentInspector and the upstream call. Default glob patterns are anchored to the MCP __ separator to avoid matching tools like shellcheck or shellharden.

  2. Response DLP (HTTPS MITM): per-response scanning of buffered response bodies and headers using InspectRedactRule regexes from the policy store. Distinct from phantom token stripping, which protects outbound requests. This protects the agent from seeing real credentials that upstreams leak in responses.

Key design points

  • Rule management across all channels: sluice policy add redact <pattern> --replacement "...", Telegram /policy redact <pattern> [replacement], and HTTP API 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.
  • Field-scoped scanning for ExecInspector: preferred command slots (command, cmd, script, code, etc.), reconstructed argv (command + joined args), smuggle slots (input, stdin, body, data, payload), and recursive descent into nested maps up to depth 8. Prose slots (description, notes, comment) are excluded to avoid false positives.
  • Bounded decompression for Response DLP: gzip, brotli, deflate (zlib-wrapped per RFC 9110), and zstd. Up to 2 stacked encodings. Each decoder wraps io.LimitReader capped at maxProxyBody (16 MiB). Post-decompression size check as the final cap.
  • Case-insensitive matching for slot keys, env blacklist, and encoding tokens. Go struct defaults like Command/Args are caught.
  • Audit redaction: exec_block events include only the category (trampoline, dangerous_cmd, env_override, metachar), never the raw match. Prevents audit logs from leaking credentials embedded in blocked payloads.

Known limitation: streaming responses

Responses with Content-Type: text/event-stream or bodies exceeding go-mitmproxy's StreamLargeBodies (5 MiB) enter streaming mode, which skips the buffered Response callback. DLP scanning is not applied to these responses. The current mitigation is a one-per-connection WARNING log when DLP rules are configured but a response streams. Proper stream-aware DLP (chunk-by-chunk regex with overlap buffering and mid-stream decompression) is listed in the plan's Future work.

Wiring

  • cmd/sluice/main.go and cmd/sluice/mcp.go: construct mcp.NewExecInspector(nil) with defaults and pass into GatewayConfig.ExecInspector.
  • internal/proxy/server.go: load InspectRedactRules from the store at startup, propagate to SluiceAddon.SetRedactRules. UpdateInspectRules reloads on SIGHUP.
  • SluiceAddon.Response: runs OAuth phantom swap first, then DLP scan.

Scope notes

The review phase expanded beyond the plan's original 6 tasks. Additions included compression bomb defense, stacked Content-Encoding support, deflate zlib wrapping, split-argv reconstruction, case-insensitive slots, wrapped schema recursion, chmod setuid coverage, combined short-flag trampoline detection, and CLI/Telegram redact commands. All additions are driven by review findings (phase 1 through 4 plus 6 codex iterations). See docs/plans/completed/20260405-tool-network-dlp-hardening.md for the full task breakdown.

@nnemirovsky nnemirovsky merged commit 7e043b8 into main Apr 14, 2026
6 checks passed
@nnemirovsky nnemirovsky deleted the tool-network-dlp-hardening branch April 14, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant