docs(audit): part 9 - root cause analysis, behavior-direction layer

This commit is contained in:
2026-08-22 12:54:33 -05:00
parent fd049a1331
commit 608b8ce555
+90
View File
@@ -320,3 +320,93 @@ confirmed, this item stays open.
**Containment:** local config only; never committed, never pushed. But it
did reach a session log, which is precisely the leak channel this section
warns about — logged here so the gate failure is on record.
---
# PART 9: FULL ROOT-CAUSE ANALYSIS - THE BEHAVIOR-DIRECTION LAYER
## (2026-08-22, deep examination session)
Method note: this pass used READING, not grepping. Keyword sweeps missed
everything below because nothing signs its work. Findings are behavioral.
## RC#1: REMOTE BEHAVIOR INJECTION (proven end-to-end)
config/config.ts (~L360-395): for every auth entry of type "wellknown",
the app fetches {provider}/.well-known/opencode, reads remote_config
{url, headers}, fetches that URL, and MERGES the returned JSON into the
GLOBAL config layer.
The remote config schema (core/src/v1/config/config.ts) includes:
- instructions[] (behavioral instruction files)
- agent{} (agent definitions incl. system prompts)
- permission{} (what the agent may do)
- mcp{} (which external servers get wired)
- default_agent, server{ hostname, mdns, cors }
Any authenticated provider can silently reshape agent behavior on the
user's machine. Logged only at Effect.logDebug level - invisible at
normal verbosity. Live code path in every binary built tonight.
Endpoint state 2026-08-22: opencode.ai serves 404 to anonymous curl -
BUT responses are server-discretionary per client (fingerprinting is
referenced in their own webfetch tool); dormancy cannot be assumed.
## RC#2: NETWORK EXPOSURE VIA SAME VECTOR
Remote/global config carries server{hostname, mdns}. mdns:true flips
binding to 0.0.0.0 and broadcasts via Bonjour as "opencode-{port}"
(server/mdns.ts, default domain opencode.local). A remote config can
expose the entire agent API to the LAN without any CLI flag.
Default without mdns: 127.0.0.1 (loopback).
## RC#3: THIRD-PARTY DATA OUTFLOW
tool/mcp-websearch.ts: websearch defaults through mcp.exa.ai and
search.parallel.ai. Sends queries + session_id + model_name outbound.
EXA_API_KEY passed IN URL QUERY STRING (leaks to intermediary logs).
Responses parsed loosely (SSE lines) into agent context with minimal
validation = second injection surface.
## RC#4: TELEMETRY ON LLM TRAFFIC
agent/agent.ts + session/llm.ts attach OpenTelemetry tracers to model
calls. Export destination via OTEL_EXPORTER_OTLP_ENDPOINT/HEADERS env.
control-plane/workspace.ts (L533-535) PROPAGATES these variables to
remote workspaces. Trace metadata of AI conversations is remotely
redirectable by whoever controls the control plane.
## RC#5: FLEET-MANAGEMENT ARCHITECTURE
- server/mdns.ts: LAN self-broadcast (Bonjour)
- control-plane/workspace.ts: persistent SSE connections to remote
targets at /global/event, header-authenticated, per-workspace
ConnectionStatus tracking; pluggable workspace adapters
- server/routes/instance/httpapi: wide route surface incl.
/experimental/console/orgs, /experimental/console/switch,
/experimental/workspace/warp, /experimental/worktree/reset,
/auth/:providerID, /command, /file, /api/event
Authorization middleware present but named Experimental*;
coverage not yet audited line-by-line.
- plugin/meta.ts: plugin fingerprinting + first_seen/last_seen/
load_count usage tracking
- server/shared/fence.ts + fence middleware: x-opencode-sync event-
sequence headers syncing instances to controllers
## SHAPE VERDICT
A local coding agent implemented as a managed fleet node: instructable
remotely, exposable remotely, observable remotely. Every mechanism
dressed as configuration; every trace hidden at debug log level.
## REMEDIATION ORDER (for rebuild)
1. Config from local ledger only; remote proposals visible+approved,
never silent merges. DELETE well-known fetch path.
2. Loopback-only binding as constitutional default; no config may
widen it. mDNS deleted or opt-in-per-session with loud warning.
3. No third-party intermediaries without explicit per-session consent.
Keys never in URLs. MCP results validated or rejected.
4. Telemetry physically absent from source, not toggle-off.
5. All fleet plumbing (control-plane SSE, org routes, sync headers,
fingerprinting) deleted; replaced by user-owned EventBus visibility.
## STILL UNEXAMINED (queued next sessions)
acp/ internals (3.5k lines), cli/ (20k lines), session/ end-to-end
data flow, cli/tui/worker.ts listener chain, server/routes/instance/
httpapi handler-by-handler audit.
## GUARD STATUS
Our egress guard (src/guard/index.ts, installed at CLI entrypoint)
already logs all outbound requests to ~/.local/state/neuron-guard.jsonl
and blocks vendor hosts in NEURON_GUARD=strict mode. It would have
caught RC#1/RC#3 traffic on day one.