docs(audit): part 9 - root cause analysis, behavior-direction layer
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user