Skip to content

v3.0.0

Choose a tag to compare

@cyyever cyyever released this 04 Mar 09:11
· 296 commits to main since this release
564b7cb

Highlights

  • MCP Ecosystem β€” crust mcp namespace unifies the MCP gateway, adds
    crust mcp-discover (auto-patches Claude/Cursor/Windsurf configs) and
    crust mcp-http (Streamable HTTP gateway)
  • Critical SSE Buffer Fix β€” Buffer overflow previously bypassed the rule
    engine; now retries the full request as non-streaming for complete evaluation
    (fail-closed)
  • Fail-Closed Shell Parsing β€” Unparseable shell commands now block by
    default instead of passing through, closing a rule-bypass vector
  • OS Keyring β€” API keys stored in OS keyring (macOS Keychain, Windows
    DPAPI, Linux Secret Service) with file fallback; no more plaintext env vars
    at rest
  • Locked Rules β€” New rule category that survives --disable-builtin,
    protecting self-management endpoints and git hooks
  • 4 New Builtin Rules β€” System config, persistence, reverse shell, and
    SSRF protection
  • 13 Security Gaps Closed β€” Percent-encoded self-protect bypass, nc/socat
    UNIX socket variants, macOS Keychain/GNOME Keyring/1Password/KeePassXC
    paths, .netrc, browser credential DBs, Anthropic DLP pattern fix, and more
  • NTFS ADS Defense β€” Strips alternate data stream suffixes
    (file.txt:Zone.Identifier) before path matching on Windows
  • Filesystem-Aware Case Sensitivity β€” internal/pathutil probes the
    actual filesystem to decide case-folding rather than using compile-time OS
    constants

⚠️ Breaking Change

crust mcp-gateway has been renamed to crust mcp.
Update any scripts, systemd units, shell aliases, or CI configs that reference
the old command name.

New Features

  • crust mcp β€” unified MCP command namespace (replaces crust mcp-gateway)
  • crust mcp-discover β€” auto-discovers installed MCP servers and patches
    Claude/Cursor/Windsurf configs
  • crust mcp-http β€” MCP Streamable HTTP gateway
  • OS keyring secret storage with file fallback; ANTHROPIC_API_KEY /
    OPENAI_API_KEY env vars still accepted as fallback
  • Locked rules: rules that survive --disable-builtin (self-management, git
    hooks, agent configs)
  • 4 new builtin locked rules: protect-system-config, protect-persistence,
    block-reverse-shell, block-ssrf-metadata
  • Auto-restore agent configs on daemon shutdown
  • Desktop app token protection (VS Code, JetBrains, browser credential DBs)
  • $HOME expansion in YAML rule patterns
  • Locked rule count exposed in API and TUI rule list header
  • Atomic file lock-on-open (O_EXLOCK/O_SHLOCK) eliminating TOCTOU on rule
    file reads/writes
  • ACP E2E test suite with mock agent
  • FreeBSD CI

Security Fixes

  • Critical: SSE buffer overflow now retries as non-streaming β€” previously
    FlushAll() sent uninspected buffered events and io.Copy streamed the
    remainder unfiltered (security bypass)
  • Critical: Percent-encoded self-protect bypass (%63%72%75%73%74 for
    "crust") β€” URL-decode before regex match
  • High: Fail-closed on unparseable shell commands β€” unanalyzable input
    now blocks instead of passing through
  • High: nc.traditional / nc.openbsd reverse shell bypass β€” word
    boundary \bnc\b didn't match dotted variants
  • High: ncat --exec= bypass β€” regex required trailing space, missed
    = form
  • High: nc -U, ncat --unixsock, socat UNIX: added to socket
    self-protection regex
  • High: Dynamic self-protection rules (rules-dir delete, rule-file write,
    socket access) now locked so --disable-builtin cannot remove them
  • High: Trailing-dot FQDN bypass of SSRF metadata rule
    (metadata.google.internal.) β€” strip trailing dot before hostname match
  • High: HTML escaping corruption β€” json.Marshal was encoding &, <,
    > as \u0026/\u003c/\u003e in intercepted responses and
    non-streaming retry bodies; fixed with SetEscapeHTML(false) throughout
  • Medium: NTFS alternate data stream suffix stripping
    (file.txt:Zone.Identifier)
  • Medium: macOS Keychain, GNOME Keyring, KDE Wallet, 1Password,
    KeePassXC, LastPass paths added to protection rules
  • Medium: GitHub CLI hosts.yml, .netrc, Edge/Brave Login Data /
    Cookies, Gradle/Maven credential files added
  • Medium: Anthropic DLP pattern fixed (sk-ant-api03 β†’
    sk-ant-api\d{2}) to match future key versions
  • Medium: Fish history XDG path fix; fish conf.d added to persistence
    protection
  • Medium: git credentials severity upgraded to critical
  • Medium: 4 additional security gaps closed (action gaps, missing paths,
    over-blocking)
  • Client disconnect now cancels non-streaming retry (was using
    context.Background())
  • Unknown YAML fields in rule files now warn instead of silently dropping
    (catches typos like stale alert_webhook:)
  • SSE scanner errors checked; sync.Once for session close; upstream
    failures logged

Refactoring

  • internal/selfprotect extracted as an independent package
  • internal/proxy renamed to internal/httpproxy
  • Evaluate() modularized into 3 phase methods (PreparePaths,
    EvaluateConditions, ApplyDLP)
  • Null byte stripping unified to single stripNullBytes function
  • Hardcoded path protections unified into pathGuard registry
  • internal/message module for centralized block message formatting
  • internal/pathutil for filesystem-based case sensitivity detection
  • Phantom newtype IDs (TraceID, SessionID, SpanID) prevent parameter
    swap bugs
  • InterceptionContext, SSEBufferConfig, SSERequestContext structs
    replace positional constructor args
  • Sum types for shellExecResult, bufferState, NewMatch/NoMatch

Testing

  • ACP E2E tests with mock agent
  • FuzzInterceptAnthropicResponse uses real rule engine + HTML-escaping
    invariant (\u0026 must not appear in re-serialized output)
  • FuzzBufferEvent now exercises size-limit overflow path on every seed
  • TestBufferedSSEWriter_Timeout verifies fail-closed: flush after timeout
    writes zero bytes
  • TestRetryAsNonStreaming_RespectsClientContext verifies client disconnect
    cancels retry
  • TestRetryAsNonStreaming_ErrorStatusCodes covers 429/500 upstream
    propagation
  • Bypass regression tests for FQDN trailing-dot and dynamic rule lockout
  • FreeBSD CI added; macOS CI gated to main branch