If you discover a security vulnerability in ocserve, please report it privately via GitHub's private vulnerability reporting:
https://github.com/Reliary/ocserve/security/advisories/new
Do not open a public GitHub issue.
We will acknowledge receipt within 48 hours and provide an estimated timeline for a fix.
- The
ocservebinary (server, CLI, MCP-capable tool host, importer) - The embedded, version-matched opencode web UI served at
/ - The plugin sidecar host (
ocserve-plugin) and MCP client (ocserve-mcp) - The PTY group (
ocserve-pty) - Build and release infrastructure
- LLM provider API keys (user-managed; ocserve never logs them)
- Third-party dependencies (managed via
cargo-denyand Dependabot) - The upstream opencode project itself (see its own policy)
- ocserve reads the user's existing
~/.config/opencodeconfig, auth, and model cache read-only and never writes to them. - Default bind is loopback. Exposure to a network is an operator decision
(e.g. a Tailscale ACL or a socat forwarder); when bound non-loopback the auth
policy is the frozen upstream contract (
offby default, password viaOCSERVE_SERVER_PASSWORDwhen set). Fail-fast (2026-10-18): binding a non-loopback address withauth_mode=offis refused at boot, because the credential store echoes provider API keys on GET, so an open network-reachable bind would expose them. Useauth_mode="basic"(with a mode-600 password file), or keep the bind loopback and expose via the tailnet forwarder (the deployed pattern). - The credential store (
credentialtable) holds provider API keys. The DB directory is locked to 0700 and the unit setsUMask=0077; SQLite's recreated WAL/SHM inherit owner-only access.GET /api/credentialechoes values (upstream parity). That is safe only because the server is loopback or auth-gated. - Access to filesystem routes is contained to the session worktree
(
D-FS-CONTAIN; writers additionally resolve the deepest existing ancestor so a symlink cannot redirect a create out of the tree); MCP tool trust is TOFU-pinned with an enforce mode.
The parity ledger (PLAN.md §17, bench/*/allow.txt) names every intentional
difference from upstream. One is security-relevant and documented, not hidden:
D-PTY-1: the PTY connect-token accepts a request with noOrigin. That is safe on a loopback bind and a hazard on a non-loopback bind.
- SAST: CodeQL runs on every push/PR (
.github/workflows/codeql-analysis.yml) - Dependency scanning: Dependabot +
cargo-denyadvisories/sources/bans - Secret scanning: gitleaks on every PR diff (
.github/workflows/pr-secret-scan.yml) - Supply chain:
cargo-audit+cargo-denyin CI and nightly - Fuzz:
cargo-fuzztargets for the parsers (weekly) - Unsafe:
#![forbid(unsafe_code)]on every crate that can carry it; the sole opt-in (ocserve-ptyFFI,ocserve-httpglibcmalloc_trim) is documented per-site and asserted in CI - Least privilege: every workflow token is scoped to the minimum
main is protected: pull request required, the CI status checks
(gates, replay, capdiff, pair) must pass, and direct pushes are
restricted. See .github/workflows/.