Skip to main content
Concept · Explanation

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.