River Review's security model
This page explains why River Review itself is safe by design. For how to report a vulnerability, see SECURITY.md.
Skills are not executable code
A River Review skill is a Markdown file — frontmatter plus a prompt body. There are no scripts/ directories under skills/, and a skill never runs a shell or code.
"Executing" a skill means sending its prompt and the diff to an LLM to obtain review text. The pipeline uses no eval / vm / dynamic require, and there is no code-execution sink that consumes the diff. The deterministic detectors are regex matches only, and the git / rg calls use array-argument execFile with no shell.
Reviews are read-only
Review output is a set of <file>:<line>: <message> findings. Output that does not match the format is dropped, and the fallback is limited to deterministic heuristics. River Review does not change code; it only surfaces findings and a verdict as decision material.
Humans keep the final decision (human-in-the-loop)
- The GitHub Action defaults to
dry_run: true. - It posts to the PR as a
COMMENTonly — there is no approve or auto-merge path. - The deterministic gate can only escalate to human review; it has no way to push a decision toward GO.
So no finding can automatically approve, merge, or change code.
Handling untrusted diffs
The diff is untrusted input placed into the prompt. That is the prompt-injection surface common to all LLM-based review, not a River-Review-specific defect. The worst a malicious diff can achieve is a wrong review comment that a human reads — because:
- Output is comment-only; injection cannot cause a merge or approval.
- Findings pass format validation, so free-form injected prose is dropped.
- The verifier rejects findings whose evidence references files not in the diff (verifier).
- The review rules forbid speculation beyond the diff.
- Secret redaction runs on both the input and the output.
- No dynamic code execution or deserialization happens, so an RCE-style "malicious payload" does not apply.
Common misconceptions
- "Large change → run all skills" is not code execution. It means applying all review lenses (test coverage, naming, flakiness, and so on); no privileged operation or shell is involved.
- It is not a replacement for static analysis. Deterministic syntactic / type / known-pattern checks stay with dedicated tools; River Review complements them with semantic consistency.