Skip to content

Security

Michael Kinney edited this page Oct 15, 2026 · 1 revision

Security

OpenCodifier is designed to run fully local and offline — but it still parses hostile input: decision schemas, candidate descriptions, graph definitions, and model manifests (PLANNING.md §66). The security posture is therefore structural, not aspirational.

Related pages: Architecture (the failure posture) · Interfaces (the transports and their gates) · Contributing (the aegis gate in the workflow).

Reporting a vulnerability

Report privately via GitHub security advisories rather than public issues. Include a minimal reproducer (input file + invocation) and the affected crate/version.

  • Initial response within 7 days.
  • Coordinated disclosure: a fix targeted within 90 days of a confirmed report; reporters credited in the release notes unless asked not to.

The five invariants

Contributors must preserve these; violations are security bugs (from SECURITY.md):

  1. No telemetry, no cloud calls. The runtime must not open network connections except when the user explicitly installs a model or starts a server with an explicit host flag.
  2. Data is not executable. Text from state, candidate descriptions, tool descriptions, and schemas must never modify policy, thresholds, graph structure, filesystem paths, or tool permissions.
  3. Input is hostile. Schema and graph parsers enforce resource limits (max input bytes, nodes, candidates, questions, execution time) and never panic on malformed input — a typed error with a stable code, always.
  4. Model integrity. Model downloads are explicit and verified against the SHA-256 in a manifest before use (Models).
  5. Local bind default. opencodifier serve binds 127.0.0.1 unless the operator passes an explicit non-local flag.

How each transport inherits the posture:

Surface Structural property
HTTP binds 127.0.0.1:8177 by default; any non-loopback bind requires an explicit --allow-remote (documented as a real risk); 1 MiB body cap at the socket
MCP stdio only — no socket to bind, no flag that opens it outward; local by construction
WASM no filesystem, no network, no storage API, no output channel; pure wasm, no -sys crates
FFI guards at the boundary; thread-local last error; header/implementation drift impossible by test

Input hostility

Treat all input as hostile (PLANNING.md §73). Concrete consequences in the engine:

  • Hostile state text is content, not instruction — a focused-extraction view feeds a classifier and nothing else; no policy, threshold, or graph decision is ever read from state text.
  • Unknown wire fields are ignored forward-compatibly, except the native IR, which denies unknown fields.
  • Safe mode (the default) refuses semantic-pruning graphs at assembly; the opt-out is per-engine and never per-request — input cannot switch it (Engine).
  • Client-supplied graph identity is content-addressed (SHA-256), never client-asserted — a decision made under graph A can never be served for graph B.
  • Rate/limits: max graph nodes 128, max execution time 120 s (D32), max batch 16 — validated at the wire, still min-ed with the server's own config.

The aegis scanning gate

CI runs aegis — the project's own high-performance pattern scanner — against a committed baseline:

aegis --format json scan --file . --baseline .aegis/baseline.json   # 0 new findings
  • Findings are line-anchored: any line shift re-flags, so the baseline is regenerated in the same commit as the edit that shifted lines (regenerate in-tree; the gate and the generation must use the same --config).
  • New findings fail the supply-chain lane. Triaged appends are recorded per entry with a triage note.
  • Discipline rule learned in practice: the gate runs after every content edit, not only before "the final" one — docs have tripped real pipeline runs.

Supply-chain lanes

  • cargo deny check — licenses, advisories, bans, sources (a TLS-backend license outside the allowlist is a rejection reason, not a feature negotiation — D26).
  • cargo audit — known-vulnerability audit of the dependency graph.
  • All CI tools are baked into the runner-local image at pinned versions (including aegis at a pinned rev) — zero runtime tool installs, and job containers cannot reach host services at all.
  • No credentials or tokens ever live in repo files, docs, or logs.

Supported versions

SECURITY.md records the supported line as 0.1.x. Treat that table as the policy document of record and check it before relying on a fix backport — the project has released well past 0.1.x (Releases) and the table updates lag the release train.

Clone this wiki locally