Granska runs real scanner CLIs and an LLM review pipeline against attacker-controlled content — the whole point of an audit tool is to point it at code you don’t fully trust. That makes Granska’s own execution environment attack surface too, not just the thing producing a report about someone else’s. This page summarizes the honest, disclosed threat model; the full document (with the CodeRabbit RCE precedent this hardening was built in response to) is linked below.
What’s defended
- Host-FS compromise via scanners — the local tier runs scanners inside
a kernel-enforced sandbox (non-root,
--cap-drop ALL,--read-onlyroot filesystem,--network noneby default, resource-bounded). The CI tier uses a non-root user plus a read-only checkout copy (Unix DAC) — a disclosed, weaker-but-capability-free substitute, since GitHub’s container-action mechanism exposes no--cap-drop/--read-onlyknobs. - Egress/exfiltration — local-tier scanning is air-gapped by default
(vulnerability DBs baked into the image), only
--scope +dastre-opens networking. - LLM-lane prompt injection — every review lane frames target content as untrusted data, never instructions, backed by a dedicated prompt-injection detection lane (OWASP LLM01-tagged).
- Reduced auditor runtime privilege — CI’s
allowedToolsis shrunk to the minimum needed to run and report.
What’s explicitly NOT defended
- Novel container escapes / kernel 0-days.
- Supply-chain compromise of the pinned scanner binaries themselves.
- CI-tier network egress from a compromised scanner process (no capability-free deny mechanism exists inside a single container-action invocation — a named, unclosed residual).
Why this matters
In 2025, a disclosed RCE in a comparable AI code-review product let a malicious pull request execute arbitrary code inside that product’s own production environment via a crafted linter config — reaching credentials across its install base. “The auditor is attack surface” is not hypothetical; Granska’s Phase 4 hardening exists because of exactly this threat class.
Full document, including every residual named explicitly:
docs/THREAT-MODEL.md
in the repo.