Skip to content

Architecture

Overview

Oktsec is a single Go binary with no CGO dependencies. It operates in four modes, all sharing the same security pipeline.

graph TB
    subgraph "oktsec binary"
        serve["serve<br>(HTTP proxy)"]
        proxy["proxy<br>(stdio)"]
        gateway["gateway<br>(MCP)"]
        mcp["mcp<br>(tool server)"]
    end

    serve --> pipeline
    proxy --> pipeline
    gateway --> pipeline
    mcp --> pipeline

    subgraph pipeline["Security Pipeline"]
        direction LR
        rl[Rate Limit] --> id[Identity<br>Ed25519]
        id --> acl[ACL]
        acl --> scan[Content Scan<br>Aguara 175 rules]
        scan --> audit[(Audit Log<br>SQLite)]
    end

Package layout

cmd/oktsec/commands/     Cobra CLI entry point
internal/
  proxy/                 HTTP proxy, stdio wrapper, forward proxy, agent CRUD API
  gateway/               MCP gateway fronting backend servers
  engine/                Aguara detection engine wrapper
  audit/                 SQLite audit trail + quarantine queue
  identity/              Ed25519 keypair management
  config/                YAML config loading/validation
  policy/                ACL evaluator
  dashboard/             HTMX web UI (server-rendered)
  mcp/                   MCP tool server (6 security tools)
  discover/              Auto-discovers MCP clients on the machine
  auditcheck/            41 deployment audit checks (SARIF output)
  graph/                 Agent topology + threat scoring
  mcputil/               Shared MCP utilities
  safefile/              SSRF/symlink-safe file I/O
rules/                   Detection rule YAML files (embedded via embed.go)
sdk/                     Go SDK client
sdk/python/              Python SDK

Security pipeline detail

The pipeline in internal/proxy/handler.go runs checks from cheapest to most expensive. If any check fails, the message is rejected immediately — no further processing.

flowchart TD
    msg[Incoming Message] --> rl{Rate limit?}
    rl -->|exceeded| r429[429 Too Many Requests]
    rl -->|ok| sig{Valid signature?}
    sig -->|invalid| r403a[403 identity_rejected]
    sig -->|missing + required| r401[401 signature_required]
    sig -->|ok / not required| sus{Agent suspended?}
    sus -->|yes| r403b[403 agent_suspended]
    sus -->|no| acl{ACL allows?}
    acl -->|no| r403c[403 acl_denied]
    acl -->|yes| scan[Aguara Scan<br>175 rules]
    scan --> bc[Blocked Content<br>per-agent categories]
    bc --> split[Split Injection<br>multi-message scan]
    split --> override[Rule Overrides<br>from config]
    override --> hist[History Escalation<br>3+ blocks in 1h]
    hist --> verdict{Verdict}
    verdict -->|clean| v200[200 delivered]
    verdict -->|flag| v200f[200 content_flagged]
    verdict -->|quarantine| v202[202 quarantined]
    verdict -->|block| v403[403 content_blocked]

    scan --> audit[(Audit Log)]
    v200 --> audit
    v200f --> audit
    v202 --> audit
    v403 --> audit
    v403 --> webhook[Webhook Alert]
    v202 --> webhook

Data flow by mode

HTTP proxy (serve)

The main mode. Agents send JSON messages via REST API. Dashboard and agent CRUD API are co-hosted.

flowchart LR
    agent[Agent] -->|POST /v1/message| proxy[Oktsec Server]
    proxy --> pipeline[Security Pipeline]
    pipeline --> db[(SQLite)]
    proxy -->|/dashboard| dash[HTMX Dashboard]
    proxy -->|/v1/agents| api[Agent CRUD API]
    proxy -->|/metrics| prom[Prometheus]

Stdio proxy (proxy)

Wraps an MCP server process. Sits between the MCP client and server, intercepting JSON-RPC 2.0 messages on stdin/stdout.

flowchart LR
    client[MCP Client] <-->|stdin/stdout| oktsec[oktsec proxy]
    oktsec <-->|stdin/stdout| server[MCP Server]
    oktsec --> scan[Aguara Scan]
    oktsec --> db[(Audit Log)]

MCP gateway (gateway)

Fronts multiple backend MCP servers through a single Streamable HTTP endpoint. Auto-discovers tools from all backends.

flowchart LR
    agent[Agent] -->|HTTP /mcp| gw[Oktsec Gateway]
    gw --> scan[Security Pipeline]
    gw -->|stdio| fs[Filesystem Server]
    gw -->|stdio| db_srv[Database Server]
    gw -->|HTTP| gh[GitHub MCP]
    scan --> audit[(Audit Log)]

Forward proxy (egress)

HTTP forward proxy for outbound agent traffic. Supports per-agent domain policies and DLP scanning.

flowchart LR
    agent[Agent] -->|HTTP/CONNECT| fp[Forward Proxy]
    fp --> header{X-Oktsec-Agent?}
    header -->|yes| agent_policy[Per-Agent Policy]
    header -->|no| global[Global Policy]
    agent_policy --> domain{Domain allowed?}
    global --> domain
    domain -->|no| block[403 Blocked]
    domain -->|yes| scan[Content Scan]
    scan --> internet[Internet]
    fp --> audit[(Audit Log)]

Key design decisions

No CGO
All dependencies are pure Go. Cross-compilation to Linux, macOS, Windows on amd64 and arm64 works out of the box. The SQLite driver is modernc.org/sqlite (pure Go translation of SQLite C code).
Official MCP SDK
Uses modelcontextprotocol/go-sdk (Tier 1, Linux Foundation governance, semver stability). Migrated from community mark3labs/mcp-go for long-term support.
Embedded rules
Detection rules are compiled into the binary via rules/embed.go. No external files to deploy or manage. Custom rules can be loaded from a directory at runtime.
Cheapest checks first
The pipeline runs rate limiting (~1ns) before signature verification (~120us) before content scanning (~8ms). This minimizes wasted CPU on rejected messages.
Batched audit writes
The SQLite audit store batches inserts for ~90K writes/sec throughput. Queries use 24-hour time windows with covering indexes for <6ms latency at 1M+ rows.

Performance

Metric Value
Audit write throughput ~90K inserts/sec (batched)
Handler throughput (clean) ~52 msg/sec per core
Handler throughput (malicious) ~127 msg/sec per core
Signature verification ~120us
Query latency at 1M rows <6ms
Binary size ~30 MB
Memory at idle ~25 MB