Security
September 19, 2026 · View on GitHub
Reporting
Please report vulnerabilities through GitHub's private security advisories for
nrdz-labs/fast-jev-opencode:
https://github.com/nrdz-labs/fast-jev-opencode/security/advisories/new. Do not
open a public issue for a vulnerability. Credential leaks are the most likely
class here.
What this plugin touches
- Reads the OpenCode
contexthook payload (the request about to be sent) and may rewrite tool-call / tool-result parts in the outgoing request only. It never mutates the stored session history, and never touches the compaction path. - Reads
config.jsonfrom its own plugin folder. It does not write it; the file is local configuration you own. - Writes
log.jsonl(rotated tolog.1.jsonl), and — only whendebugDumpMessages: true—debug/, inside its own plugin folder.log.jsonlholds only operational fields: counts, character sizes, timings, decision probabilities, the run's model label (providerID/id) and the configured model string, the configured host, the session id, and tool-call identifiers (tool names and tool-call ids). It never holds prompts, tool results, tool inputs, file contents, the configuredgoal, the fullbaseUrlor raw error text.debug/holds the raw conversation verbatim: leave the flag off outside a deliberate fixture capture, and deletedebug/afterwards. - Persists per-call decisions (tool-call ids + probabilities) in the plugin storage OpenCode provides for its location.
- Reads
TYPESAFE_API_KEYfrom the environment, then from~/.config/opencode/.env. The key is sent only to the configuredbaseUrl(defaulthttps://api.typesafe.ai/v1/systemone). The default is HTTPS; if you pointbaseUrlat a plain-HTTP endpoint the key travels in cleartext, so keep the default or another HTTPS endpoint you trust. - Fails open: a missing key, timeout, transport error, HTTP error, malformed
answer, invalid answer, malformed tool payload or unreadable
config.jsonleaves the request untouched. Errors are logged as a fixed category only (for examplejev-http (500)orinternal); the plugin never stringifies an arbitrary caught error, so a body, URL or cause cannot leak into the log.
What is sent to Jev
The transport contract is separate from the log contract: Jev receives more
than the log does. Each ask posts { model, state, questions } to the
configured endpoint. The state is built by the vendored state.ts:
goal: the configured goal verbatim, or, when unset, the last three real user prompts joined together, each truncated to 500 chars.history: one entry per message with its role and text. Message text — the latest real prompt included — is sent in full until the state is fitted tomaxStateTokens; shrinking then abridges texts oldest-first (a 400-char head plus a 150-char tail) and finally collapses or omits older entries.- per tool call: its
id, tool name, a JSON excerpt of the arguments (truncated to 1000, then 200, then 60 chars, or omitted), and the result noteok|error, N chars (omitted). Tool-result bodies are not included — only that indicator and size.
Non-text, non-tool content such as media/file attachments is skipped, so attachments are not forwarded as attachments. Ordinary message text and tool arguments are sent within those limits and can contain user code, paths, prose or serialised file content. Treat the Jev endpoint as receiving that material, the same way your model provider does. Provider-executed parts are skipped.