Security posture
Senkani is a trust boundary. v0.2.0 defaults are all secure: prompt-injection guard on, SSRF hardening on, secret redaction on, schema migrations versioned + crash-safe. Opt-outs are explicit env vars, not hidden flags.
What "trust boundary" means
The agent on one side; your filesystem, network, and secrets on the other. Everything that crosses the boundary is scanned, redacted, validated, or rejected. The boundary is not a feature; it's the product.
Prompt-injection guard
SENKANI_INJECTION_GUARD=on by default. Scans every MCP tool response for instruction-override patterns ("ignore previous instructions", "you are now…"), tool-call injection (fake function-call syntax inside returned text), context-manipulation (zero-width chars, homoglyph substitutions), and exfiltration (base64-looking blobs that decode to URLs or credentials). Anti-evasion normalization: lowercase, zero-width-char strip, Cyrillic→Latin homoglyph fold, NFKC normalization. Single linear pass.
SSRF hardening
senkani_web resolves the target host via getaddrinfo before fetch and blocks any address in private/link-local/CGNAT/multicast ranges (including IPv4-mapped IPv6, octal/hex IPv4, IPv4-compatible IPv6). Redirects are re-validated via WKNavigationDelegate.decidePolicyFor — a 3xx Location header to 10.x, 169.254.169.254, or ::ffff:… is cancelled. A WKContentRuleList blocks subresource requests (img/script/xhr) to the same ranges, so a hostile HTML page embedding <img src="http://169.254.169.254/…"> cannot reach cloud metadata through WebKit's auto-rendering. file:// scheme is rejected entirely.
Secret redaction
13 regex families + entropy-based fallback. Short-circuits with firstMatch so no-match inputs don't pay the full regex cost (1 MB benign input: ~25 ms). Every tool output runs through before reaching the model. The counter command_redactions on event_counters increments on each redaction.
Schema migrations — versioned + crash-safe
Session DB uses PRAGMA user_version + a schema_migrations audit log. Cross-process coordination via flock sidecar. On failed migration, a kill-switch lockfile is written and subsequent boots refuse to run migrations until the operator inspects the DB. This trades convenience for safety deliberately.
Retention
RetentionScheduler prunes token_events (90 d default), sandboxed_results (24 h default), validation_results (24 h default) on an hourly tick. Tune via ~/.senkani/config.json → "retention": {…}.
Socket authentication — opt-in
SENKANI_SOCKET_AUTH=on generates a 32-byte random token at ~/.senkani/.token (mode 0600), rotated on every server start. Every connection to mcp.sock/hook.sock/pane.sock must send a length-prefixed handshake frame matching the token. Raises the bar from ambient same-UID socket access to must-read-token-file. Default off in v0.2.0 for backward compatibility; flipping to on next release.
Observability
Every security-defense site increments an event_counters row: injection detections, SSRF blocks, socket handshake rejections, schema migrations, retention prunes, command redactions. Surfaced via senkani stats --security with Gelman-style count/total (pct%) rate annotation, or the senkani_session action:"stats" MCP action.
Data portability
senkani export streams sessions + commands + token_events as JSONL via a read-only SQLite connection — doesn't block the live MCP server. --redact collapses user paths. GDPR-adjacent by design, not by regulation.