Skip to content

Security Model

Comprehensive security architecture ensuring zero-trust, policy-driven protection for AI agents.


Overview

Symbiont implements a security-first architecture designed for regulated and high-assurance environments. The security model is built on zero-trust principles with comprehensive policy enforcement, multi-tier sandboxing, and cryptographic auditability.

Security Principles

  • Zero Trust: All components and communications are verified
  • Defense in Depth: Multiple security layers with no single point of failure
  • Policy-Driven: Declarative security policies enforced at runtime
  • Complete Auditability: Every operation logged with cryptographic integrity
  • Least Privilege: Minimal permissions required for operation

Multi-Tier Sandboxing

The runtime ships three host-isolation tiers (Tier 1 → Tier 3) plus one hosted-execution backend (E2B). The tiers form a monotonically increasing isolation ladder; E2B is not a peer on that ladder — it executes on third-party infrastructure and is documented separately below.

graph TB
    A[Risk Assessment Engine] --> B{Risk Level}

    B -->|Low Risk| C[Tier 1: Docker]
    B -->|Medium Risk| D[Tier 2: gVisor]
    B -->|High Risk| E[Tier 3: Firecracker]

    A -.->|Opt-in via DSL| H[Hosted: E2B]

    subgraph "Tier 1: Container Isolation"
        C1[Container Runtime]
        C2[Resource Limits]
        C3[Network Isolation]
        C4[Read-only Filesystem]
    end

    subgraph "Tier 2: User-space Kernel"
        D1[System Call Interception]
        D2[Memory Protection]
        D3[I/O Virtualization]
        D4[Enhanced Isolation]
    end

    subgraph "Tier 3: microVM"
        E1[KVM Hardware Virtualization]
        E2[Dedicated Kernel]
        E3[Read-only Rootfs]
        E4[Per-execution Lifecycle]
    end

    subgraph "Hosted: third-party cloud"
        H1[No on-host isolation]
        H2[Trust assumption: provider]
        H3[Quick-start, no setup]
    end

    C --> C1
    D --> D1
    E --> E1
    H --> H1

All three host-isolation tiers — Docker, gVisor, and Firecracker — ship in the OSS runtime. Operators pick the tier per agent via the DSL with { sandbox = ... } block, or set a project default via [sandbox] tier = "..." in symbiont.toml. E2B is opt-in only via the DSL (with { sandbox = "e2b" }) and is intentionally not exposed as an [sandbox] tier value.

Tier 1: Docker Isolation

Use Cases: - Trusted development tasks - Low-sensitivity data processing - Internal tool operations

Security Features:

docker_security:
  memory_limit: "512MB"
  cpu_limit: "0.5"
  network_mode: "none"
  read_only_root: true
  security_opts:
    - "no-new-privileges:true"
    - "seccomp:default"
  capabilities:
    drop: ["ALL"]
    add: ["SETUID", "SETGID"]

Threat Protection: - Process isolation from host - Resource exhaustion prevention - Network access control - Filesystem protection

Tier 2: gVisor Isolation

Use Cases: - Standard production workloads - Sensitive data processing - External tool integration

Security Features: - User-space kernel implementation - System call filtering and translation - Memory protection boundaries - I/O request validation

Configuration:

gvisor_security:
  runtime: "runsc"
  platform: "ptrace"
  network: "sandbox"
  file_access: "exclusive"
  debug: false
  strace: false

Advanced Protection: - Kernel vulnerability isolation - System call interception - Memory corruption prevention - Side-channel attack mitigation

Prerequisites: Install runsc and register it as a Docker runtime in /etc/docker/daemon.json. symbi doctor reports whether runsc is reachable.

Tier 3: Firecracker microVM

Use Cases: - Highest-isolation workloads (untrusted code, multi-tenant, regulated data) - Where syscall-filter granularity (gVisor) is insufficient and a real kernel boundary is required - Per-execution VM lifecycle for stronger blast-radius containment

Security Features: - Hardware virtualization via KVM - Per-execution microVM with operator-supplied kernel + rootfs - Read-only root filesystem by default - No shared kernel surface with the host

Configuration: [sandbox.firecracker] in symbiont.toml:

[sandbox]
tier = "tier3"

[sandbox.firecracker]
kernel_image_path = "/var/lib/firecracker/vmlinux"
rootfs_path       = "/var/lib/firecracker/rootfs.ext4"
vcpus             = 1
mem_mib           = 512
rootfs_read_only  = true

Prerequisites: Operator must supply (a) a Firecracker-compatible kernel image and (b) a root filesystem image with an init script that reads the agent payload. See docs/firecracker-setup.md for a step-by-step quickstart, the in-VM init contract, and a hardening checklist. symbi doctor reports whether the firecracker binary is reachable.

Once you have both artifacts, scaffold a tier3 project with:

symbi init --profile assistant --sandbox tier3 \
  --firecracker-kernel /var/lib/firecracker/vmlinux \
  --firecracker-rootfs /var/lib/firecracker/rootfs.ext4

symbi init validates that both files exist before writing symbiont.toml, so misconfigurations surface at scaffold time rather than first agent run.

Hosted execution: E2B

E2B is a hosted cloud-sandbox backend, not a host-isolation tier. It sits outside the Tier 1 → Tier 3 ladder and is documented here for completeness.

What it is: Code runs on E2B's infrastructure via their HTTPS API; the runtime ships only an HTTP client. Set E2B_API_KEY and select it per agent with with { sandbox = "e2b" }. There is no --sandbox e2b flag on symbi init — E2B is intentionally opt-in via DSL only, since it represents a different trust model than the on-host tiers.

Use cases: - Quick-start demos and evaluation without installing Docker, gVisor, or Firecracker. - Development environments where the operator can't run a sandbox host (CI without privileged mode, locked-down laptops, ARM developer machines).

What it is not: - Not a substitute for on-host isolation. Code, prompts, and tool outputs traverse E2B's infrastructure. Don't use it for workloads with privacy, residency, or compliance requirements. - Not comparable to Tier ½/3 in a security review. The runtime maps E2B → SecurityTier::Hosted, which sorts below Tier1 for ordering — policies that require host isolation (tier >= Tier1) will reject hosted execution.

Configuration: No project-level config; set E2B_API_KEY in the environment and use with { sandbox = "e2b" } per agent.


Policy Engine

Policy Architecture

The policy engine provides declarative security controls with runtime enforcement:

graph TB
    A[Policy Definition] --> B[Policy Parser]
    B --> C[Policy Store]
    C --> D[Policy Engine]
    D --> E[Enforcement Points]

    E --> F[Agent Creation]
    E --> G[Resource Access]
    E --> H[Message Routing]
    E --> I[Tool Invocation]
    E --> J[Data Operations]
    E --> CPG[Inter-Agent Policy]

    K[Audit Logger] --> L[Policy Violations]
    E --> K

Policy Types

Access Control Policies

Define who can access what resources under which conditions:

policy secure_data_access {
    allow: read(sensitive_data) if (
        user.clearance >= "secret" &&
        user.need_to_know.contains(data.classification) &&
        session.mfa_verified == true
    )

    deny: export(data) if data.contains_pii == true

    require: [
        user.background_check.current,
        session.secure_connection,
        audit_trail = "detailed"
    ]
}

Data Flow Policies

Control how data moves through the system:

policy data_flow_control {
    allow: transform(data) if (
        source.classification <= target.classification &&
        user.transform_permissions.contains(operation.type)
    )

    deny: aggregate(datasets) if (
        any(datasets, |d| d.privacy_level > operation.privacy_budget)
    )

    require: differential_privacy for statistical_operations
}

Resource Usage Policies

Manage computational resource allocation:

policy resource_governance {
    allow: allocate(resources) if (
        user.resource_quota.remaining >= resources.total &&
        operation.priority <= user.max_priority
    )

    deny: long_running_operations if system.maintenance_mode

    require: supervisor_approval for high_memory_operations
}

Policy Evaluation Engine

pub trait PolicyEngine {
    async fn evaluate_policy(
        &self, 
        context: PolicyContext, 
        action: Action
    ) -> PolicyDecision;

    async fn register_policy(&self, policy: Policy) -> Result<PolicyId>;
    async fn update_policy(&self, policy_id: PolicyId, policy: Policy) -> Result<()>;
}

pub enum PolicyDecision {
    Allow,
    Deny { reason: String },
    AllowWithConditions { conditions: Vec<PolicyCondition> },
    RequireApproval { approver: String },
}

Performance Optimization

Policy Caching: - Compiled policy evaluation for performance - LRU cache for frequent decisions - Batch evaluation for bulk operations - Sub-millisecond evaluation times

Incremental Updates: - Real-time policy updates without restart - Versioned policy deployment - Rollback capabilities for policy errors

Cedar Policy Engine (cedar Feature)

Symbiont integrates the Cedar policy language for formal authorization. Cedar enables fine-grained, auditable access control policies that are evaluated at the reasoning loop's policy gate.

cargo build --features cedar

Key capabilities: - Formal verification: Cedar policies can be statically analyzed for correctness - Fine-grained authorization: Entity-based access control with hierarchical permissions - Reasoning loop integration: CedarPolicyGate implements the ReasoningPolicyGate trait, evaluating each proposed action against Cedar policies before execution - Audit trail: All Cedar policy decisions are logged with full context

use symbi_runtime::reasoning::cedar_gate::CedarPolicyGate;

// Create a Cedar policy gate with deny-by-default stance
let cedar_gate = CedarPolicyGate::deny_by_default();
let runner = ReasoningLoopRunner::builder()
    .provider(provider)
    .executor(executor)
    .policy_gate(Arc::new(cedar_gate))
    .build();

Inter-Agent Communication Policy

The CommunicationPolicyGate enforces authorization rules for all inter-agent communication. Every call through ask, delegate, send_to, parallel, or race is evaluated against policy rules before execution.

Rule structure: - Conditions: SenderIs(agent), RecipientIs(agent), Always, composite All/Any - Effects: Allow or Deny { reason } - Priority: Rules evaluated highest-priority first; first match wins - Default: Allow (backward compatible — existing projects work unchanged)

Policy denial is a hard fail — the calling agent receives an error through the ORGA loop and can reason about it. All inter-agent messages are cryptographically signed via Ed25519 and encrypted with AES-256-GCM.

Example policy: prevent a worker agent from delegating to other agents:

forbid(
    principal == Agent::"worker",
    action == Action::"delegate",
    resource
);


Cryptographic Security

Digital Signatures

All security-relevant operations are cryptographically signed:

Signature Algorithm: Ed25519 (RFC 8032) - Key Size: 256-bit private keys, 256-bit public keys - Signature Size: 512 bits (64 bytes) - Performance: 70,000+ signatures/second, 25,000+ verifications/second

pub struct MessageSignature {
    pub signature: Vec<u8>,
    pub algorithm: SignatureAlgorithm,
    pub public_key: Vec<u8>,
}

impl AuditEvent {
    pub fn sign(&mut self, private_key: &PrivateKey) -> Result<()> {
        let message = self.serialize_for_signing()?;
        self.signature = private_key.sign(&message);
        Ok(())
    }

    pub fn verify(&self, public_key: &PublicKey) -> bool {
        let message = self.serialize_for_signing().unwrap();
        public_key.verify(&message, &self.signature)
    }
}

Key Management

Key Storage: - Hardware Security Module (HSM) integration - Secure enclave support for key protection - Key rotation with configurable intervals - Distributed key backup and recovery

Key Hierarchy: - Root signing keys for system operations - Per-agent keys for operation signing - Ephemeral keys for session encryption - External keys for tool verification

Planned feature — The KeyManager API shown below is part of the security roadmap and not yet available in the current release. The current implementation provides key utilities via KeyUtils in crypto.rs.

// PLANNED — not yet implemented in the current release
pub struct KeyManager {
    hsm: HardwareSecurityModule,
    key_store: SecureKeyStore,
    rotation_policy: KeyRotationPolicy,
}

impl KeyManager {
    pub async fn generate_agent_keys(&self, agent_id: AgentId) -> Result<KeyPair>;
    pub async fn rotate_keys(&self, key_id: KeyId) -> Result<KeyPair>;
    pub async fn revoke_key(&self, key_id: KeyId) -> Result<()>;
}

Encryption Standards

Symmetric Encryption: AES-256-GCM - 256-bit keys with authenticated encryption - Unique nonces for each encryption operation - Associated data for context binding

Asymmetric Encryption: X25519 + ChaCha20-Poly1305 - Elliptic curve key exchange - Stream cipher with authenticated encryption - Perfect forward secrecy

Message Encryption:

pub fn encrypt_message(
    plaintext: &[u8], 
    recipient_public_key: &PublicKey,
    sender_private_key: &PrivateKey
) -> Result<EncryptedMessage> {
    let shared_secret = sender_private_key.diffie_hellman(recipient_public_key);
    let nonce = generate_random_nonce();
    let ciphertext = ChaCha20Poly1305::new(&shared_secret)
        .encrypt(&nonce, plaintext)?;

    Ok(EncryptedMessage {
        nonce,
        ciphertext,
        sender_public_key: sender_private_key.public_key(),
    })
}


Audit and Compliance

Cryptographic Audit Trail

Every security-relevant operation generates an immutable audit event:

pub struct AuditEvent {
    pub event_id: Uuid,
    pub timestamp: SystemTime,
    pub agent_id: AgentId,
    pub event_type: AuditEventType,
    pub details: serde_json::Value,
    pub signature: Ed25519Signature,
    pub previous_hash: Hash,
    pub event_hash: Hash,
}

Audit Event Types: - Agent lifecycle events (creation, termination) - Policy evaluation decisions - Resource allocation and usage - Message sending and routing - External tool invocations - Security violations and alerts

Hash Chaining

Events are linked in an immutable chain:

impl AuditChain {
    pub fn append_event(&mut self, mut event: AuditEvent) -> Result<()> {
        event.previous_hash = self.last_hash;
        event.event_hash = self.calculate_event_hash(&event);
        event.sign(&self.signing_key)?;

        self.events.push(event.clone());
        self.last_hash = event.event_hash;

        self.verify_chain_integrity()?;
        Ok(())
    }

    pub fn verify_integrity(&self) -> Result<bool> {
        for (i, event) in self.events.iter().enumerate() {
            // Verify signature
            if !event.verify(&self.public_key) {
                return Ok(false);
            }

            // Verify hash chain
            if i > 0 && event.previous_hash != self.events[i-1].event_hash {
                return Ok(false);
            }
        }
        Ok(true)
    }
}

Compliance Features

Regulatory Support:

HIPAA (Healthcare): - PHI access logging with user identification - Data minimization enforcement - Breach detection and notification - Audit trail retention for 6 years

GDPR (Privacy): - Personal data processing logs - Consent verification tracking - Data subject rights enforcement - Data retention policy compliance

SOX (Financial): - Internal control documentation - Change management tracking - Access control verification - Financial data protection

Custom Compliance:

Planned feature — The ComplianceFramework API shown below is part of the security roadmap and not yet available in the current release.

// PLANNED — not yet implemented in the current release
pub struct ComplianceFramework {
    pub name: String,
    pub audit_requirements: Vec<AuditRequirement>,
    pub retention_policy: RetentionPolicy,
    pub access_controls: Vec<AccessControl>,
    pub data_protection: DataProtectionRules,
}

impl ComplianceFramework {
    pub fn validate_compliance(&self, audit_trail: &AuditChain) -> ComplianceReport;
    pub fn generate_compliance_report(&self, period: TimePeriod) -> Report;
}

Human Approval Relay (symbi-approval-relay)

When a policy decision returns require: approval, the action blocks until a human reviewer either approves or denies it. symbi-approval-relay is the crate that carries those requests to a human and the decision back, while keeping both hops auditable.

Dual-channel design

The relay is dual-channel by design: every approval round-trips through two independent paths, and both must agree before the runtime unblocks the action.

  • Primary channel — an interactive surface for the reviewer (chat adapter, web UI, CLI prompt). This is where the reviewer reads the request and decides.
  • Attestation channel — an independent verification path (for example a signed callback, a second operator, or an out-of-band confirmation). The runtime will not unblock on a primary-channel approval alone.

This structure defeats the single-channel compromise case — an attacker who seizes the primary channel still cannot grant approvals, because the attestation channel doesn't share trust with it.

What the relay carries

Every approval request in flight carries: - The agent identity (AgentPin-anchored) and the policy decision that triggered the request - The full action context — tool invocation, resource, arguments — hashed so reviewers can confirm they approved this action and not a swapped one - A deadline after which the request auto-denies - Correlation IDs so the audit trail ties the two channels' decisions back to a single action

Approvals and denials are recorded in the same cryptographically tamper-evident audit chain as every other runtime decision. A human saying "yes" is a decision in the log, not a bypass of it.

Where it's used

  • Cedar policies that emit RequireApproval { approver: "..." } verdicts
  • Destructive or high-privilege tool calls gated by ToolClad approval hooks
  • Scheduled jobs configured with one_shot = true plus an approval policy
  • Any DSL policy block that names require: <role>_approval

If no relay is configured, approval-gated actions fail closed — they're denied, not silently allowed.


Tool Security

Symbiont provides two complementary layers for tool security:

  • SchemaPin — cryptographic verification of MCP tool schemas (identity and integrity)
  • ToolClad — declarative tool contracts with argument validation, scope enforcement, injection prevention, and Cedar policy generation

ToolClad governs how tools execute (input validation, scope boundaries, evidence capture). SchemaPin governs whether to trust a tool's identity (signature verification, key pinning).

SchemaPin Verification Process

External tools are verified using cryptographic signatures:

sequenceDiagram
    participant Tool as Tool Provider
    participant SP as SchemaPin
    participant AI as AI Reviewer
    participant Runtime as Symbiont Runtime
    participant Agent as Agent

    Tool->>SP: Submit Tool Schema
    SP->>AI: Security Analysis
    AI-->>SP: Analysis Results
    SP->>SP: Human Review (if needed)
    SP->>SP: Sign Schema
    SP-->>Tool: Signed Schema

    Agent->>Runtime: Request Tool Use
    Runtime->>SP: Verify Tool Schema
    SP-->>Runtime: Verification Result
    Runtime-->>Agent: Allow/Deny Tool Use

Trust-On-First-Use (TOFU)

Key Pinning Process: 1. First encounter with a tool provider 2. Verify provider's public key through external channels 3. Pin the public key in local trust store 4. Use pinned key for all future verifications

Planned feature — The TOFUKeyStore API shown below is part of the security roadmap and not yet available in the current release.

// PLANNED — not yet implemented in the current release
pub struct TOFUKeyStore {
    pinned_keys: HashMap<ProviderId, PinnedKey>,
    trust_policies: Vec<TrustPolicy>,
}

impl TOFUKeyStore {
    pub async fn pin_key(&mut self, provider: ProviderId, key: PublicKey) -> Result<()> {
        if self.pinned_keys.contains_key(&provider) {
            return Err("Key already pinned for provider");
        }

        self.pinned_keys.insert(provider, PinnedKey {
            public_key: key,
            pinned_at: SystemTime::now(),
            trust_level: TrustLevel::Unverified,
        });

        Ok(())
    }

    pub fn verify_tool(&self, tool: &MCPTool) -> VerificationResult {
        if let Some(pinned_key) = self.pinned_keys.get(&tool.provider_id) {
            if pinned_key.public_key.verify(&tool.schema_hash, &tool.signature) {
                VerificationResult::Trusted
            } else {
                VerificationResult::SignatureInvalid
            }
        } else {
            VerificationResult::UnknownProvider
        }
    }
}

AI-Driven Tool Review

Automated security analysis before tool approval:

Analysis Components: - Vulnerability Detection: Pattern matching against known vulnerability signatures - Malicious Code Detection: ML-based malicious behavior identification - Resource Usage Analysis: Assessment of computational resource requirements - Privacy Impact Assessment: Data handling and privacy implications

Planned feature — The SecurityAnalyzer API shown below is part of the security roadmap and not yet available in the current release.

// PLANNED — not yet implemented in the current release
pub struct SecurityAnalyzer {
    vulnerability_patterns: VulnerabilityDatabase,
    ml_detector: MaliciousCodeDetector,
    resource_analyzer: ResourceAnalyzer,
    privacy_assessor: PrivacyAssessor,
}

impl SecurityAnalyzer {
    pub async fn analyze_tool(&self, tool: &MCPTool) -> SecurityAnalysis {
        let mut findings = Vec::new();

        // Vulnerability pattern matching
        findings.extend(self.vulnerability_patterns.scan(&tool.schema));

        // ML-based detection
        let ml_result = self.ml_detector.analyze(&tool.schema).await?;
        findings.extend(ml_result.findings);

        // Resource usage analysis
        let resource_risk = self.resource_analyzer.assess(&tool.schema);

        // Privacy impact assessment
        let privacy_impact = self.privacy_assessor.evaluate(&tool.schema);

        SecurityAnalysis {
            tool_id: tool.id.clone(),
            risk_score: calculate_risk_score(&findings),
            findings,
            resource_requirements: resource_risk,
            privacy_impact,
            recommendation: self.generate_recommendation(&findings),
        }
    }
}

ClawHavoc Skill Scanner

The ClawHavoc scanner provides content-level defense for agent skills. Every skill file is scanned line-by-line before loading, and findings at Critical or High severity block the skill from executing.

Severity Model

Level Action Description
Critical Fail scan Active exploitation patterns (reverse shells, code injection)
High Fail scan Credential theft, privilege escalation, process injection
Medium Warn Suspicious but potentially legitimate (downloaders, symlinks)
Warning Warn Low-risk indicators (env file references, chmod)
Info Log Informational findings

Detection Categories (40 Rules)

Original Defense Rules (10) - pipe-to-shell, wget-pipe-to-shell — Remote code execution via piped downloads - eval-with-fetch, fetch-with-eval — Code injection via eval + network - base64-decode-exec — Obfuscated execution via base64 decoding - soul-md-modification, memory-md-modification — Identity tampering - rm-rf-pattern — Destructive filesystem operations - env-file-reference, chmod-777 — Sensitive file access, world-writable permissions

Reverse Shells (7) — Critical severity - reverse-shell-bash, reverse-shell-nc, reverse-shell-ncat, reverse-shell-mkfifo, reverse-shell-python, reverse-shell-perl, reverse-shell-ruby

Credential Harvesting (6) — High severity - credential-ssh-keys, credential-aws, credential-cloud-config, credential-browser-cookies, credential-keychain, credential-etc-shadow

Network Exfiltration (3) — High severity - exfil-dns-tunnel, exfil-dev-tcp, exfil-nc-outbound

Process Injection (4) — Critical severity - injection-ptrace, injection-ld-preload, injection-proc-mem, injection-gdb-attach

Privilege Escalation (5) — High severity - privesc-sudo, privesc-setuid, privesc-setcap, privesc-chown-root, privesc-nsenter

Symlink / Path Traversal (2) — Medium severity - symlink-escape, path-traversal-deep

Downloader Chains (3) — Medium severity - downloader-curl-save, downloader-wget-save, downloader-chmod-exec

Executable Whitelisting

The AllowedExecutablesOnly rule type restricts which executables an agent skill can invoke:

// Only allow these executables — everything else is blocked
ScanRule::AllowedExecutablesOnly(vec![
    "python3".into(),
    "node".into(),
    "cargo".into(),
])

Custom Rules

Domain-specific patterns can be added alongside ClawHavoc defaults:

let mut scanner = SkillScanner::new();
scanner.add_custom_rule(
    "block-internal-api",
    r"internal\.corp\.example\.com",
    ScanSeverity::High,
    "References to internal API endpoints are not allowed in skills",
);

Invisible-Character Sanitization (symbi-invis-strip)

symbi-invis-strip is a zero-dependency utility crate used across the runtime to strip characters that render as nothing but change meaning — the classic payload for prompt-injection and policy-evasion attacks.

What it removes

  • ASCII C0 (0x00–0x1F) and DEL (0x7F), except for \t \n \r
  • ASCII C1 (0x80–0x9F)
  • Zero-width characters (ZWSP, ZWNJ, ZWJ)
  • Bidirectional overrides (LRO, RLO, PDF, LRE, RLE, LRI, RLI, FSI, PDI)
  • Word joiner and the invisible-operator block
  • Byte-order marks (BOM)
  • Variation selectors (VS1–VS16 and supplementary VS17–VS256)
  • Characters in the Unicode Tag block (U+E0000–U+E007F)

Where it runs

  • Inbound chat and webhook payloads — before they reach the orchestrator
  • Tool-call arguments — before they reach Cedar evaluation
  • Skill and agent DSL content — before the scanner and parser

Optional markup stripping

The opt-in sanitize_field_with_markup variant additionally removes: - <!-- ... --> HTML comments - Triple-backtick fenced code blocks

Markup stripping is appropriate for surfaces where renderer-hidden markup has no legitimate use — for example, short policy rationale fields or display-only metadata. It is not applied to fields that legitimately carry markdown or code (like agent source, policy bodies, or tool outputs).


Cedar Policy Linter

scripts/lint-cedar-policies.py is a static analysis pass that runs on every .cedar file in the repository. It catches a class of attack where a malicious (or compromised) authoring flow writes a policy that looks correct but contains characters that produce a different authorization decision than the reviewer expects.

What it catches

  • Homoglyph identifiers — Cyrillic а (U+0430) masquerading as Latin a, Greek ο (U+03BF) as Latin o, and similar lookalikes in principal/action/resource names.
  • Invisible control characters inside identifiers, string literals, or between tokens.

Where it runs

  • Pre-commit hook — blocks commits that introduce either class of issue.
  • CI — the same check is a required test job, so commits that bypass the hook (via --no-verify) still fail CI.

Combined with symbi-invis-strip on the data path, the linter closes the authoring-path vector: invisible tricks can't enter the repo, and any that slip through at runtime are stripped before policy evaluation.


Network Security

Secure Communication

Transport Layer Security: - TLS 1.3 for all external communications - Mutual TLS (mTLS) for service-to-service communication - Certificate pinning for known services - Perfect forward secrecy

Message-Level Security: - End-to-end encryption for agent messages - Message authentication codes (MAC) - Replay attack prevention with timestamps - Message ordering guarantees

pub struct SecureChannel {
    encryption_key: [u8; 32],
    mac_key: [u8; 32],
    send_counter: AtomicU64,
    recv_counter: AtomicU64,
}

impl SecureChannel {
    pub fn encrypt_message(&self, plaintext: &[u8]) -> Result<EncryptedMessage> {
        let counter = self.send_counter.fetch_add(1, Ordering::SeqCst);
        let nonce = self.generate_nonce(counter);

        let ciphertext = ChaCha20Poly1305::new(&self.encryption_key)
            .encrypt(&nonce, plaintext)?;

        let mac = Hmac::<Sha256>::new_from_slice(&self.mac_key)?
            .chain_update(&ciphertext)
            .chain_update(&counter.to_le_bytes())
            .finalize()
            .into_bytes();

        Ok(EncryptedMessage {
            nonce: nonce.to_vec(),
            ciphertext,
            sender_public_key: self.local_public_key(),
        })
    }
}

Network Isolation

Sandbox Network Control: - No network access by default - Explicit allow-list for external connections - Traffic monitoring and anomaly detection - DNS filtering and validation

Network Policies:

network_policy:
  default_action: "deny"
  allowed_destinations:
    - domain: "api.openai.com"
      ports: [443]
      protocol: "https"
    - ip_range: "10.0.0.0/8"
      ports: [6333]  # Qdrant (only needed if using optional Qdrant backend)
      protocol: "http"

  monitoring:
    log_all_connections: true
    detect_anomalies: true
    rate_limiting: true


Incident Response

Security Event Detection

Automated Detection: - Policy violation monitoring - Anomalous behavior detection - Resource usage anomalies - Failed authentication tracking

Alert Classification:

pub enum ViolationSeverity {
    Info,       // Normal security events
    Warning,    // Minor policy violations
    Error,      // Confirmed security issues
    Critical,   // Active security breaches
}

pub struct SecurityEvent {
    pub id: Uuid,
    pub timestamp: SystemTime,
    pub severity: ViolationSeverity,
    pub category: SecurityEventCategory,
    pub description: String,
    pub affected_components: Vec<ComponentId>,
    pub recommended_actions: Vec<String>,
}

Incident Response Workflow

graph TB
    A[Security Event] --> B[Event Classification]
    B --> C{Severity Level}

    C -->|Info/Low| D[Log Event]
    C -->|Medium| E[Alert Security Team]
    C -->|High| F[Automatic Mitigation]
    C -->|Critical| G[Emergency Response]

    F --> H[Isolate Affected Components]
    F --> I[Revoke Compromised Credentials]
    F --> J[Preserve Evidence]

    G --> H
    G --> K[Notify Leadership]
    G --> L[External Incident Response]

Recovery Procedures

Automated Recovery: - Agent restart with clean state - Key rotation for compromised credentials - Policy updates to prevent recurrence - System health verification

Manual Recovery: - Forensic analysis of security events - Root cause analysis and remediation - Security control updates - Incident documentation and lessons learned


Security Best Practices

Development Guidelines

  1. Secure by Default: All security features enabled by default
  2. Principle of Least Privilege: Minimal permissions for all operations
  3. Defense in Depth: Multiple security layers with redundancy
  4. Fail Securely: Security failures should deny access, not grant it
  5. Audit Everything: Complete logging of security-relevant operations

Deployment Security

Environment Hardening:

# Disable unnecessary services
systemctl disable cups bluetooth

# Kernel hardening
echo "kernel.dmesg_restrict=1" >> /etc/sysctl.conf
echo "kernel.kptr_restrict=2" >> /etc/sysctl.conf

# File system security
mount -o remount,nodev,nosuid,noexec /tmp

Container Security:

# Use minimal base image
FROM scratch
COPY --from=builder /app/symbiont /bin/symbiont

# Run as non-root user
USER 1000:1000

# Set security options
LABEL security.no-new-privileges=true

Operational Security

Monitoring Checklist: - [ ] Real-time security event monitoring - [ ] Policy violation tracking - [ ] Resource usage anomaly detection - [ ] Failed authentication monitoring - [ ] Certificate expiration tracking

Maintenance Procedures: - Regular security updates and patches - Key rotation on schedule - Policy review and updates - Security audit and penetration testing - Incident response plan testing


Security Configuration

Environment Variables

# Cryptographic settings
export SYMBIONT_CRYPTO_PROVIDER=ring
export SYMBIONT_KEY_STORE_TYPE=hsm
export SYMBIONT_HSM_CONFIG_PATH=/etc/symbiont/hsm.conf

# Audit settings
export SYMBIONT_AUDIT_ENABLED=true
export SYMBIONT_AUDIT_STORAGE=/var/audit/symbiont
export SYMBIONT_AUDIT_RETENTION_DAYS=2555  # 7 years

# Security policies
export SYMBIONT_POLICY_ENFORCEMENT=strict
export SYMBIONT_DEFAULT_SANDBOX_TIER=gvisor
export SYMBIONT_TOFU_ENABLED=true

Security Configuration File

[security]
# Cryptographic settings
crypto_provider = "ring"
signature_algorithm = "ed25519"
encryption_algorithm = "chacha20_poly1305"

# Key management
key_rotation_interval_days = 90
hsm_enabled = true
hsm_config_path = "/etc/symbiont/hsm.conf"

# Audit settings
audit_enabled = true
audit_storage_path = "/var/audit/symbiont"
audit_retention_days = 2555
audit_compression = true

# Sandbox security
default_sandbox_tier = "gvisor"
sandbox_escape_detection = true
resource_limit_enforcement = "strict"

# Network security
tls_min_version = "1.3"
certificate_pinning = true
network_isolation = true

# Policy enforcement
policy_enforcement_mode = "strict"
policy_violation_action = "deny_and_alert"
emergency_override_enabled = false

[tofu]
enabled = true
key_verification_required = true
trust_on_first_use_timeout_hours = 24
automatic_key_pinning = false

Security Metrics

Key Performance Indicators

Security Operations: - Policy evaluation latency: <1ms average - Audit event generation rate: 10,000+ events/second - Security incident response time: <5 minutes - Cryptographic operation throughput: 70,000+ ops/second

Compliance Metrics: - Policy compliance rate: >99.9% - Audit trail integrity: 100% - Security event false positive rate: <1% - Incident resolution time: <24 hours

Risk Assessment: - Vulnerability patching time: <48 hours - Security control effectiveness: >95% - Threat detection accuracy: >99% - Recovery time objective: <1 hour


Future Enhancements

Advanced Cryptography

Post-Quantum Cryptography: - NIST-approved post-quantum algorithms - Hybrid classical/post-quantum schemes - Migration planning for quantum threats

Homomorphic Encryption: - Privacy-preserving computation on encrypted data - CKKS scheme for approximate arithmetic - Integration with machine learning workflows

Zero-Knowledge Proofs: - zk-SNARKs for computation verification - Privacy-preserving authentication - Compliance proof generation

AI-Enhanced Security

Behavior Analysis: - Machine learning for anomaly detection - Predictive security analytics - Adaptive threat response

Automated Response: - Self-healing security controls - Dynamic policy generation - Intelligent incident classification


Next Steps

The Symbiont security model provides enterprise-grade protection suitable for regulated industries and high-assurance environments. Its layered approach ensures robust protection against evolving threats while maintaining operational efficiency.