Skip to content
Security

Security

How Frontal isolates, encrypts, and audits every agent action.

Principles

Three invariants, never violated.

Every architectural decision in DECISIONS.md traces back to one of these.

Isolation by default

Every agent runs in its own git worktree AND its own Docker container with default-deny network egress.

Secrets never exposed

Provider keys live only in the gateway. Secrets vault uses Fernet/AES. Never appear in prompts, logs, or the event log.

Everything audited

HMAC-SHA256 chained event log. Append-only. Tamper-evident. The single source of truth.

Sandbox

Each task is a sealed box.

Task Worktree · isolated directory Docker Container · default-deny Allowlisted Egress · proxy sidecar

Sandbox containers start with --network none (empty allowlist) or on an internal Docker network with an egress proxy sidecar (non-empty allowlist). The proxy matches hostnames only — never TLS interception. Containers cannot reach the host filesystem except via the mounted worktree volume.

Encryption

Secrets & encryption.

Keys and credentials have exactly one path in — and never leak sideways.

Fernet/AES vault (D-017)

Secrets are resolved from the vault into the launcher environment at exec time ONLY — never written to .mcp.json, logs, the event log, memory, or Pi context.

Master key

Loaded from the FRONTAL_MASTER_KEY environment variable, with the OS keychain as a fallback. Never committed, never logged.

Provider keys (D-002)

Held in os.environ and scrubbed before subprocess launch. See backend/runner.py _env.

Audit records names, never values

The audit chain records THAT a secret was used (by name) — never its value. You can prove a credential was invoked without exposing it.

Model Gateway

Gateway-only model access.

The engine talks to one host: its own local gateway. (D-002)

Pi Engine → models.json → Local Gateway · http://localhost:<port>/v1
GLM → MiniMax → OpenCode

Single entry point

Pi's models.json points exclusively at the local gateway. No provider key ever reaches the engine subprocess.

Per-provider circuit breakers

20-call sliding window, 50% error threshold, timed cooldown, half-open probe. One provider going down never takes the pipeline with it.

Tier failover chain

GLM → MiniMax → OpenCode, configurable in backend/config/model_routing.json. Virtual tiers frontal/heavy|standard|utility|asr.

Single metering point

Every model call is metered in one place — feeding budgets (80% warn / 100% pause) and billing. No side-channels, no untracked tokens.

Audit

Tamper-evident by construction.

The event log is the source of truth. Everything else is rebuildable. (D-004)

HMAC-SHA256 chained JSONL

Append-only. Each event's HMAC incorporates the previous event's hash. Tampering breaks the chain at the first altered record.

Log locations

Per-project: .frontal/events/*.jsonl. Orchestrator-wide: .sdd/audit/YYYY-MM-DD.jsonl.

Chain verified before rebuild

verify_chain() runs before any memory rebuild. Reconciler.run() on startup detects orphaned containers, stale worktrees, and interrupted tasks.

ArangoDB is derived

The memory graph is a rebuildable view of the event log. Losing it never loses memory — replay the chain and it comes back.

Concurrency

Worktree isolation.

Parallel where safe, serialized where it isn't. No silent force-pushes.

Task A · scope: src/api Task B · scope: src/ui ∥ Disjoint scopes · parallel
Task C · scope: src/api ≡ Task D · scope: src/api → Overlapping · serialized

Isolated worktrees

Each task gets its own git worktree under .frontal/worktrees/. No two agents share a working directory.

Bernstein scope locks

Tasks with overlapping file scopes serialize. Disjoint scopes run in parallel. The trunk lock serializes all merges to main / develop.

One rebase repair, then escalate

On conflict: one automated rebase-repair attempt. If it fails: Needs-Attention — never a silent force-push.

Disclosure

Responsible disclosure.

Found something? Tell us. We move fast and we credit honestly.

Report

Email [email protected]. PGP encouraged.

Mock address pre-launch — replace before going live.

Timelines

  • Acknowledgement: within 24 hours
  • Initial assessment: within 72 hours
  • Fix coordination: we'll work with you on the disclosure timeline (default 90 days, extendable)

Hall of fame

No acknowledged reports yet.

This section is honestly empty. The first name here will be the first.

Bug bounty

No bug bounty program yet.

We're pre-launch. We'll launch a formal program once we're stable. Until then: honest credit and our gratitude.

Compliance

Compliance roadmap.

What we support, what we're working toward, and what we don't do.

Supported

GDPR

Covered by privacy.html — data portability, deletion, objection.

Roadmap

SOC 2 Type II

Enterprise tier. Planned Q4 2026. Not yet audited.

Not planned

ISO 27001

Not currently planned. SOC 2 covers the overlapping controls.

Not supported

HIPAA

Not supported. Don't put PHI into Frontal.

Not certified

PCI DSS

Not certified. Agent-generated payment code is your responsibility to audit.

Current certifications: None. This is an honest pre-launch state.

FAQ

Security FAQ.

Do you encrypt data at rest?
Self-hosted: secrets vault is Fernet/AES. Event logs are plaintext — they're the source of truth and must be readable. Cloud: disk encryption + envelope encryption for secrets.
Can agents exfiltrate my code?
Default-deny egress means sandbox containers have no internet unless allowlisted. Even with an allowlist, the gateway proxies model calls — agents don't have direct network access to arbitrary hosts.
What if an agent generates malicious code?
Acceptance criteria + sandbox tests catch most issues. But you are responsible for reviewing generated code before production merge. One-click rollback is your safety net.

Found a vulnerability?

Report it responsibly.

Email [email protected]. We acknowledge within 24 hours and coordinate disclosure with you.

Report a vulnerability