Trust

Security

ForkReason analyzes hostile input and lets a model participate in a decision. Both are treated as attack surfaces rather than features.

Repository content is never executed

Analyzed repositories are untrusted input. ForkReason materializes a snapshot with git archive <pinned-sha> into an isolated staging repository, which yields exactly the tracked blobs at one commit. There is no working tree, no .git directory, no hooks, and no submodule content.

  • No npm install, build, or package script ever runs.
  • Every git call is an argument array with shell=false.
  • The git environment sets GIT_CONFIG_NOSYSTEM, GIT_CONFIG_GLOBAL=/dev/null and GIT_ASKPASS=/bin/false, so repository configuration cannot influence execution.
  • Symlinks, hard links, devices, absolute paths and traversal are rejected before and after path resolution.

Verified by apps/api/tests/test_safe_intake.py against archives that attempt traversal and symlink escape.

Prompt injection is a release gate

Consensus does not defend against prompt injection. If the leader and every validator read the same malicious instruction and obey it, they agree on the same wrong answer — and agreement is exactly what consensus is supposed to mean.

The defences, in the order they apply:

  1. Deterministic preprocessing. Fingerprinting strips comments and string literals before any structural comparison.
  2. Minimal excerpts. The consensus digest is capped at 12,000 characters and never contains whole files.
  3. Strong delimiters. Untrusted content is fenced inside <forkreason_evidence> tags.
  4. Explicit inert-data instruction, stated as an absolute rule above the evidence block.
  5. Strict typed parsing against an allowed enum set.
  6. Deterministic rule checks in code — chronology, contradiction between verdict and confidence, and the shared-upstream requirement.
  7. Independent validator evaluation of the substantive fields.
  8. Fail closed: unparseable or off-enum output is rejected.

Verified by contracts/tests/test_prompt_injection.py, which places the mandated attack phrases in a README, a code comment, a string constant, HTML, commit metadata and challenge evidence — and asserts that a verdict demanded by injected text is refused even when the leader has already obeyed it.

Verdicts are checked for substance

A leader is never accepted because its output parses. The validator independently derives its own decision from the same bounded evidence, applies the same deterministic guards, and compares the stable field tuple: verdict, confidence, direction, shared upstream, independent origin plausibility, and evidence classes. Rationale prose is never compared for equality.

A test drives the exact scenario that matters: a leader that returns a valid-looking but substantively incorrect verdict. The validator must reject it.

Your keys stay with you

ForkReason holds no server key that can act for a user. Every state-changing GenLayer action is signed by the browser wallet. The backend prepares payloads and indexes transaction hashes it observes; it never signs a write on a user's behalf.

The chain is the authority on revision and verdict state. The application database indexes that state for search and display, and never silently becomes an alternative source of truth.

Browser protections

  • A nonce-based Content Security Policy restricts scripts to what this server emitted for the current request. Styles allow inline because Next injects critical CSS that way.
  • frame-ancestors 'none', X-Frame-Options: DENY, nosniff, strict referrer policy and a restrictive permissions policy are set on every response.
  • No remote images, so the image optimizer is not an open proxy.
  • A decided transaction is never reported as successful unless the execution result is FINISHED_WITH_RETURN. ACCEPTED only means the committee agreed on the receipt.

Accepted residual risk

RiskStatusRationale
'unsafe-eval' in the CSP script-srcacceptedWalletConnect's SDK evaluates a dynamically built bundle. Removing it breaks wallet connectivity. Scoped to script-src; no third-party script origins are permitted.
Public GitHub API rate limits without a tokenacceptedUnauthenticated requests are limited per IP. ForkReason degrades to a clear error with bounded retry rather than hiding the problem. A token is recommended in production.
Moderate advisories in WalletConnect / Reown SDKsacceptedTransitive, no fix without breaking RainbowKit 2.2.11, and only reachable when a WalletConnect project id is configured. No critical or high advisories remain.

Disclosure

If you believe you have found a vulnerability, open a private security advisory on the repository. Please do not open a public issue for an unfixed vulnerability.

Full detail lives in SECURITY.md, docs/THREAT-MODEL.md and docs/SECURITY-FINDINGS.md.

Security · ForkReason