Security and privacy
What leaves your machine, and how ocra is isolated.
What a hostile pull request can try, and what stops it, is on Threat model.
What is sent to the model provider
- The reviewer's instructions, the change request title and description, and the diff of the files under review.
AGENTS.mdand matching.ocra/rules.jsonrules.- File content and search results that reviewers request through their tools.
- Accepted findings from
.ocra/memory.jsonfor the files under review. - For verification, each file's findings with its diff and the lines around them; for judging, the findings with the change request's title and description.
The provider is the one each model chain names; for a provider declared under providers, it is the baseUrl you configured (Model providers). At review time the opencode runtime reaches only the model providers of your chains and OpenCode's pricing catalog, models.opencode.ai; the direct runtime reaches only the declared endpoints your chains name, and nothing else at all. OpenCode also tries to install packages from npm: its own plugin package when it starts, and the code for a provider it does not ship (Model providers). ocra sends these installs to a registry on your machine that refuses them, so no code is fetched and no npm token is sent. A test runs OpenCode with every other address refused and checks this.
Nothing else is added: ocra starts its agent runtime with your global OpenCode configuration, installed skills and project instruction files disabled, so details of your machine do not end up in prompts.
Isolation
- The OpenCode runtime runs on
127.0.0.1with a random port and a random password per run, and keeps its state in a temporary directory that is removed afterwards. - OpenCode runs in an empty directory of its own, not in your checkout, with OpenCode's project configuration off. Plugins, custom tools and settings committed to the reviewed code (
.opencode/,opencode.json) never load; a test plants them and checks each of the two protections on its own. - Review tools are served from ocra's own process on
127.0.0.1, protected by a random bearer token. - The runtime receives only system basics and the credentials of the providers in your model chains, not your whole environment.
- All built-in agent tools (shell, file editing, web access) are disabled; reviewers can only read the revision under review.
- Paths requested by a model are confined to the repository. Reads never follow symbolic links: a link reads as the path it points to, as git stores it, so a link such as
notes.txt -> .envcannot expose the file behind it. - Reviewers cannot read, diff or search likely secret files (
.env, keys, certificates, cloud and registry credentials, Terraform variables and state) or anything under.git/, even when the file exists on disk or a prompt asks for it, and cannot read a file renamed away from such a name. The same patterns keep those files out of review. - Session logs are never written through a symbolic link planted in the reviewed tree.
Untrusted input
Pull request text, diffs, repository files, rules, guidelines, tool results, SARIF logs passed with --import-sarif, people's replies to findings, and everything models write about them (findings, plans, relocated quotes) are all treated as data. Instructions inside them are never followed. ocra's own sections are tagged <ocra_…>, and any text in the data that could form such a tag (including look-alike brackets, spacing, case and invisible characters) is rewritten to ‹ocra_… before it reaches a model, so data can neither leave its section nor pose as another finding. Ordinary HTML and XML in reviewed code pass through unchanged. Pull request titles and descriptions are capped in length. Text ocra prints to your terminal (findings, commit messages, errors) has control characters, escape sequences and bidirectional overrides replaced, so a change cannot rewrite your screen, hide a finding or write to your clipboard. The JSON ocra writes (--format json, session reports and logs) escapes the same characters. A reviewer reports at most 50 findings per task, with bounded text, so a steered model cannot flood a pull request.
The verdict is not a security gate
Every model in the pipeline, the reviewers, the verifier and the judge, reads the change under review, so the change can try to steer them: hide an issue from a reviewer, or argue a finding away in front of the judge. Code limits the damage: only a critical finding the verifier confirmed (or a confirmed finding the judge raised to critical) can make the verdict significant_concerns, and the judge can neither drop nor downgrade such a finding. But a clean verdict never proves a change is safe. Keep human review and dedicated security tooling for anything that must not slip through.
Shared configuration
extends fetches settings and rules over https only, never plugins, and can be pinned with #sha256=. For pull requests it is read from the base commit like the rest of the configuration.
Keys
Provider keys are read from environment variables only and never written to configuration, logs or session files. Secret files in the repository are unreadable to reviewers (see Isolation), so their contents cannot end up in prompts, reports or session files either.
CI
- Store keys as CI secrets.
- To review pull requests from forks, follow Pull requests from forks. It runs on
pull_request_target, which gives the job your secrets; that is acceptable only because ocra runs nothing from the pull request, so never add a step that does. ocra review --prand the GitHub Action read.ocra/config.json,.ocra/rules.jsonandAGENTS.mdfrom the pull request's base commit and never load repository plugins. See GitHub pull requests.ocra review --mrdoes the same for GitLab merge requests; see GitLab merge requests for the token and for merge requests from forks.
Reviewing code you do not trust
.ocra/config.json can list plugins, and plugins run code. ocra review --no-repo-config ignores that file entirely and takes models from OCRA_MODEL_*. It also stops taking .ocra/memory.json (which can silence findings), .ocra/rules.json and AGENTS.md from the code under review: with --from/--to they come from the --from commit, otherwise they are not used. ocra-eval always passes it, because benchmark repositories are third-party code.
Reporting a vulnerability
Report it privately through GitHub, never in a public issue: SECURITY.md says what is in scope and what happens next.