Skip to content

Deep Security Audit: Data Leak Analysis — Verified Findings (2026-05-13) #198

Closed

Description

@OpenCodeEngineer

Deep Security Audit — Data Leak Analysis (2026-05-13)

Full audit of every outbound HTTP call, the sharing pipeline, LLM headers, remote config, MCP tools, and bundled web UI. Each critical claim was verified against source code.


⛔ Conditional Data Leaks (opt-in, but scope is significant)

1. Share system uploads prompts, responses, tool outputs, and code diffs — MEDIUM (opt-in)

Files: packages/opencode/src/share/share-next.ts, packages/opencode/src/share/session.ts

When a session is shared (manually or via share: "auto"), the following is uploaded in real-time to https://opncd.ai:

Data Content
Session metadata title, model name, timestamps
User messages full user prompts
Assistant messages full assistant responses
Tool parts tool inputs and outputs (file reads, shell commands, etc.)
File diffs SnapshotFileDiff: filename + unified diff patch (changed lines only)

The SnapshotFileDiff type (packages/opencode/src/snapshot/index.ts:22–31) carries a unified diff patch string — changed lines, not full file contents. An earlier draft of this report incorrectly stated full file contents were sent; this has been corrected.

Auto-share triggers only if:

  • share: "auto" in config, OR
  • autoshare: true (deprecated), OR
  • OPENCODE_AUTO_SHARE=1 env var

Default: OFF. There is no path where sharing happens without explicit opt-in.


2. opencode provider routes requests through opncd.ai — MEDIUM (opt-in)

File: packages/opencode/src/session/llm.ts:374–380

When the user configures the opencode provider (requires explicit apiKey from opencode.ai), all LLM requests are routed through opencode.ai servers with these extra headers:

x-opencode-project: <first git root commit hash>  ← pseudonymous project ID
x-opencode-session: <session UUID>
x-opencode-request: <message UUID>
x-opencode-client: cli|tui|desktop|...
User-Agent: opencode/<version>

This only affects users who explicitly configure provider.opencode.options.apiKey. Users running their own Anthropic/OpenAI/etc. keys are unaffected.


3. GitHub OIDC/PAT token forwarded to api.opencode.ai — MEDIUM (CI only)

File: packages/opencode/src/cli/cmd/github.ts:363,742

When running opencode github in GitHub Actions with use_github_token mode, a GitHub PAT or OIDC token is POSTed to https://api.opencode.ai/exchange_github_app_token to exchange for a GitHub App token. This is strictly a GitHub Actions CI workflow opt-in.


4. Web search queries sent to third-party services — LOW (tool invocation)

File: packages/opencode/src/tool/mcp-websearch.ts, packages/opencode/src/tool/websearch.ts

When the LLM invokes the web search tool (requires a permission prompt):

  • Exa (mcp.exa.ai): receives the search query
  • Parallel (search.parallel.ai): receives the search query plus the local session UUID and model name

The ctx.ask permission prompt should name these third-party recipients explicitly.


5. Remote config token forwarding (enterprise wellknown) — HIGH (enterprise only)

File: packages/opencode/src/config/config.ts:538–561

When a wellknown auth entry is configured, opencode:

  1. Fetches ${url}/.well-known/opencode
  2. Calls substituteWellKnownRemoteConfig() — resolves remote_config.url and remote_config.headers from the wellknown response
  3. Makes a second fetch(remote.url, { headers: remote.headers }) — forwarding any headers the wellknown endpoint specifies

If the wellknown endpoint is compromised or malicious, it can direct the client to an attacker-controlled URL and inject arbitrary headers (including auth tokens) into that second request. This is an SSRF / token-forwarding risk in enterprise deployments only.


⚠️ Background calls (no user data, but automatic)

6. models.dev refreshes every 60 minutes — LOW

File: packages/opencode/src/provider/models.ts:105,186

On startup and every 60 minutes (Schedule.spaced("60 minutes")), opencode fetches https://models.dev/api.json to update the available model list.

Data sent: Only User-Agent: opencode/{channel}/{version}/{client} — reveals version, release channel, and client type. No prompts, no code, no credentials. Pure GET.

Disable: Not directly configurable; this is the model registry update mechanism.


7. Auto-update check on TUI startup — LOW

File: packages/opencode/src/cli/upgrade.ts, packages/opencode/src/installation/index.ts

On every TUI launch, opencode checks for a newer version by hitting npm/brew/GitHub/Chocolatey registries (GET-only). Reveals version, channel, and client type in User-Agent. No user data.

Disable: autoupdate: false in config or OPENCODE_DISABLE_AUTOUPDATE=1.


✅ Confirmed Safe

Path Verdict
API keys in config Only sent as Authorization headers to their respective providers — never serialized into shares or sent elsewhere
Sentry in web UI Requires VITE_SENTRY_DSN at build time — not present in the distributed CLI binary
Honeycomb / PostHog Only in cloud backend (packages/console) and maintainer scripts — never in CLI binary
LSP binary downloads GET-only from GitHub releases, no user data
MCP server loading Only loads URLs from user-configured opencode.json
Proxy server Internal relay for workspace feature; does not silently intercept LLM traffic
OpenTelemetry Disabled unless OTEL_EXPORTER_OTLP_ENDPOINT env var is set — fully opt-in
x-opencode-* headers Project ID is first git root commit hash (pseudonymous), not a path or username; only sent to opencode provider
Share default share: "auto" is NOT the default; no implicit sharing

Recommendations

  1. Disable auto-update pings: autoupdate: false in config or OPENCODE_DISABLE_AUTOUPDATE=1
  2. Use your own provider API keys (Anthropic, OpenAI, etc.) — prompts go directly to the provider with no opencode.ai intermediary
  3. Treat share: "auto" as high-risk — it uploads full prompts, responses, and code diffs in real-time to opncd.ai
  4. Permission prompt for web search should name exa.ai / parallel.ai explicitly and note session ID is sent to Parallel
  5. Enterprise wellknown config: validate that remote_config.url is on an expected domain before following it

Audit performed 2026-05-13. Sources: direct code inspection + automated deep-dive with Claude Opus.

Activity

  1. changed the title [-]Security Audit: No backdoors found — telemetry/egress inventory (2026-05-13)[/-] [+]Deep Security Audit: Data Leak Analysis — Verified Findings (2026-05-13)[/+] on May 14, 2026
  2. OpenCodeEngineer commented on May 14, 2026

    @OpenCodeEngineer
    Author

    Resuming work on the deep security audit with a remediation pass.

    Current focus:

    1. Harden enterprise wellknown remote-config resolution against token/header forwarding to unexpected hosts.
    2. Add/expand tests around remote URL + header handling.
    3. Re-run package typecheck/tests and report exact outcomes.

    I’ll post a follow-up with concrete code-level changes.

  3. OpenCodeEngineer commented on May 14, 2026

    @OpenCodeEngineer
    Author

    Remediation update (implemented locally, 2026-05-14):

    What was hardened

    • packages/opencode/src/config/config.ts
      • wellknown remote_config.url now must be same-origin with the wellknown base URL
      • wellknown remote_config.url now rejects embedded URL credentials (username/password)
      • invalid/empty remote URLs now fail explicitly

    Tests added/updated

    • packages/opencode/test/config/config.test.ts
      • updated: wellknown remote_config supports templated env vars in headers (same-origin remote URL)
      • added: wellknown remote_config rejects cross-origin URL
      • added: wellknown remote_config rejects URL with embedded credentials

    Validation

    • cd packages/opencode && bun test test/config/config.test.ts → 83 pass / 0 fail
    • cd packages/opencode && bun typecheck → pass

    This reduces the previously reported enterprise remote-config token/header-forwarding risk by blocking cross-origin remote config fetches.

  4. dzianisv commented on Jun 21, 2026

    @dzianisv
    Owner

    Reviewed. All findings are opt-in behaviors with proper gates:

    1. Share: requires explicit share: 'auto' or manual trigger. Default OFF.
    2. Opencode provider: requires explicit API key config. Only adds pseudonymous headers.

    No unintended data leaks found. This audit serves as documentation. Keeping open as reference.

  5. dzianisv commented on Jun 22, 2026

    @dzianisv
    Owner

    This is a reference document, not an actionable fix. All findings are opt-in behaviors with proper gates. Keeping as documentation in issue history.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationpriority:lowLow prioritysecuritySecurity issue or audit item

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions