parryai.dev
Trust

What actually happens to your code when you connect Parry.

A security scanner that touches your source code is itself a security boundary. This page is the boundary's spec — written for the engineer reviewing it before signing, not for the marketing funnel. If a claim isn't here, we don't make it.

Lifecycle of one scan

Where your code lives, second by second

  1. 01

    Webhook arrives

    GitHub posts the push event to /v1/webhooks/github. Parry verifies the HMAC, enqueues a scan task on Redis. No code has crossed yet.

  2. 02

    Worker mints a fresh install token

    GitHub App installation token, scoped to one repo, valid for one hour. Used for git clone only. Never written to disk; never logged.

  3. 03

    Hardened git clone

    Cloned into a per-scan workspace dir on the worker filesystem. Clone runs with protocol allowlists, symlinks disabled, submodules off, no credential prompts. See git flags below.

  4. 04

    Sandboxed fan-out

    Each scanner runs as its own docker container. Workspace mounted read-only. No network egress by default. No Linux capabilities. Resource caps. See sandbox flags below.

  5. 05

    Findings persisted, raw reports stored

    Findings (rule, severity, title, matched-line snippet) and raw scanner JSON (≤8MB each) land in Postgres in your tenant. Used for lifecycle, SARIF export, audit evidence.

  6. 06

    Workspace destroyed

    os.RemoveAll on both the workspace dir and the artifacts dir. The full repo is gone from disk within seconds of scan completion. Only the durable rows above remain.

Sandbox guarantees

Every scanner runs with these flags

Scanners parse attacker-controlled repo content and have CVE history (parser RCEs in semgrep, gitleaks, others). Without sandboxing, a single parser bug is a 10-minute window of free compute and outbound network. The flags below turn that into: ten minutes of CPU and memory only, no privileges, no kernel attack surface, no network.

  • --cap-drop=ALL

    Strips every Linux capability. The container runs with the absolute minimum privilege set.

  • --security-opt=no-new-privileges

    Blocks setuid escalation. A breached process can't gain more rights than it started with.

  • --network=none (default)

    No DNS, no routing, no outbound. A parser-RCE inside a scanner cannot phone home, exfiltrate, or call C2. The eight scanners that genuinely need outbound (vuln databases, package registries, GitHub API, DAST target) opt in explicitly.

  • --memory=2g --pids-limit=512 --cpus=2

    A runaway scanner is bounded — can't fork-bomb, can't eat all RAM, can't starve other scans.

  • --read-only workspace mount (:ro)

    Your code is mounted into the container as read-only. The scanner sees it; nothing inside the container can modify it.

  • Per-tool 10-minute timeout + docker kill on cancel

    A hung scanner can't run forever. On timeout or cancel, the orchestrator issues a targeted docker kill so the container actually stops (not just the docker CLI).

Git clone hardening

What protects the worker from a malicious repo

git clone itself has been a CVE surface (CVE-2022-24765 and relatives). A hostile repository can ship .gitattributes, .gitmodules, or symlinks that exploit the clone process before any scanner sees the workspace. Parry sets the following on every clone:

  • protocol.allow=builtin

    Refuses ext::, file::, and similar pseudo-protocols an attacker URL might smuggle.

  • protocol.file.allow=never

    Refuses local-path protocol on fetch, even mid-clone.

  • core.symlinks=false

    Symlinks defined inside the repo are ignored — they can't escape the workspace.

  • --no-recurse-submodules

    An attacker .gitmodules can't pull additional repositories from elsewhere.

  • GIT_TERMINAL_PROMPT=0

    git refuses to prompt for credentials. A manipulated URL can't hang the worker waiting for input.

What persists

Stored after the scan

  • Findings (rule, severity, title, fingerprint)
    Postgres, your tenant

    Lifecycle tracking — open / fixed / suppressed. Without this, every scan is a re-triage.

  • Code snippets — only the matched lines
    Postgres, your tenant

    Rendered in the finding drawer so you can decide without leaving Parry. Not the full file.

  • Raw scanner reports (JSON, ≤8MB each)
    Postgres, your tenant

    Required for SARIF re-export, AI Review re-runs, scanner regression debugging, compliance audit evidence.

  • CycloneDX SBOM per scan
    Postgres, your tenant

    Hand to procurement. One-click download from the scan page.

What does not

Removed within seconds

  • The cloned source code

    Workspace dir is os.RemoveAll'd within seconds of scan completion. The full repo never leaves disk for longer than the scan itself.

  • Your install token

    Used only inside one scan, then discarded. Never written to disk; only forwarded into containers via env.

  • Files outside the matched lines

    Only the lines a scanner flagged become code_snippet rows. Everything else is dropped with the workspace.

The LLM boundary

What crosses, when, and with what redaction

When does code cross the LLM boundary?
Only when the org owner has explicitly opted into AI Review for that org. Off by default.
What gets sent?
The diff under review, plus surrounding context lines from the changed files. Whole repos are not sent.
What is stripped before transmission?
Detected secrets (sourced from gitleaks output) and .env file contents are redacted in-process before the payload reaches the model. The redaction is unit-tested in internal/llm/redact_test.go.
Which model provider?
Configured per-deployment. Org owners see which provider is in use before opting in.
Are model providers training on your code?
Parry uses provider APIs configured for no-training (zero-data-retention where the provider supports it). The opt-in screen names the provider so you can verify their current policy yourself.
Hosting + access

Where Parry runs and who can reach your data

  • Region

    Single-region today: Hetzner, Frankfurt (EU). Source code, findings, and raw reports never leave EU infrastructure. Multi-region is on the roadmap, no committed date.

  • Tenant isolation

    Every API path scopes by org id at the handler layer. memberships.role is a typed enum (owner / admin / member); destructive actions (billing, ruleset edits, finding acceptance) require the matching role. Open-mode (AUTH_DISABLED) is dev-only and refuses to start unless bound to loopback.

  • Transport

    TLS everywhere — webhooks, OAuth, API. Sessions are 32-byte random tokens; the database stores the SHA-256 hash so a snapshot leak can't replay live sessions.

  • Audit trail

    Mutations (suppress, accept, ruleset edits, billing changes, role grants) write to an audit_log table the owner can inspect via /v1/audit. Read-event logging and tamper-evidence are roadmap (Phase 5.6).

What we don't promise

The honest gap list

If your security policy depends on any of these, do not sign with us yet. Each item is on the roadmap; none are shipped.

  • Single-tenant / customer-cloud (BYOC) deployment

    Roadmap (Phase 5.4). For organisations that cannot allow source code to touch shared infrastructure, this is the only honest answer — and it isn't shipped yet. Don't sign with us before this lands if your security policy requires it.

  • Multi-region

    Single-region today (Frankfurt, Hetzner). EU-only deployment is achievable today; a multi-region or US-region deployment is not. Roadmap, no committed date.

  • Automatic data retention policy

    No nightly purge job today. Findings, scans, raw reports, and audit log accumulate. We will add per-org retention controls (default 90 days, configurable) before charging for retention as a feature. Roadmap (Phase 6.4).

  • SOC 2 / ISO 27001 certification

    Not yet. The controls many auditors check for (RBAC enforcement, audit log, hardened sandbox, no public open-mode, /readyz) are in place; the formal report is not. Engagement-mode buyers should treat this page as the security questionnaire response in lieu of the report.

  • Image pinning by digest

    Scanner images are pinned by version tag, not by digest. A registry compromise of a pinned tag would be undetected. Roadmap (Phase 1.8 follow-up).

Verify in source

The claims on this page reduce to specific files and tests. If you're reviewing Parry for procurement, point your engineer at these:

  • internal/scan/runner/orchestrator.go — sandbox flags
  • internal/scan/runner/orchestrator_test.go — flag regression test
  • cmd/worker/scan.go — git clone hardening
  • cmd/api/access/access.go — RBAC gates
  • internal/llm/redact_test.go — secret redaction proof
  • migrations/0021_member_role_enum.sql — typed role column
  • cmd/worker/artifacts.go — what persists, what doesn't
  • cmd/api/main.go — /readyz, AUTH_DISABLED loopback enforcement

Ask for a procurement walkthrough at hello@parryai.dev.