Important
AI Assist Note (Knowledge Heritage): This document is part of the "Sovereign Reality" documentation.
- @docs ARCHITECTURE:Documentation
- Failure Path: Information drift, legacy terminology, or documentation mismatch.
- Telemetry Link: Search
[SECURITY]in audit logs.
Core technical resource for the Tadpole OS Sovereign infrastructure.
Traceability via parity_guard.py.
This document reflects the security controls currently implemented in the Rust engine and frontend runtime.
The engine requires an access token outside tests. Configure one of:
NEURAL_TOKEN=your-secret-token
NEURAL_ENGINE_ACCESS_TOKEN=your-secret-tokenProtected REST requests use:
Authorization: Bearer <token>The auth middleware is implemented in server-rs/src/middleware/auth.rs and uses constant-time token comparison via the subtle crate.
During active token rotation runbooks, the engine supports a dual-token validation window:
NEURAL_TOKEN_OLD: Accepts the deprecated token to prevent service disruption of legacy clients.NEURAL_TOKEN_NEW: Accepts the newly rotated token to allow phased rolling upgrades.NEURAL_TOKEN: Matches the primary system token.
Browser WebSocket upgrades may pass auth through:
Sec-WebSocket-Protocol: bearer.<token>Unauthenticated public routes are strictly limited to:
GET /v1/engine/health
All WebSocket connections (GET /v1/engine/ws, GET /v1/engine/live-voice) are protected and require token authentication via the Sec-WebSocket-Protocol: bearer.<token> subprotocol header. Route protection is enforced in server-rs/src/router.rs.
-
Zeroized In-Memory Key Material (
server-rs/src/security/audit.rs):- Staged Ed25519 audit signing key material and hex-decoded private key buffers implement
ZeroizeandSecrecy. Memory buffers are wiped automatically uponDrop, preventing cold-boot and process memory dump key extraction.
- Staged Ed25519 audit signing key material and hex-decoded private key buffers implement
-
A2E-01 Financial Ledger Risk Containment (
server-rs/src/routes/a2a.rs):-
24-Hour Rolling Spend Limits: Tracked in
agent_economics_metatable (default $10.00 cap / 10,000,000 micros) with automatic 24-hour resets. -
Lock-Aware Spend Projection: Before issuing a Two-Phase Commit (2PC) lock, the router calculates Total Projected Spend:
$$\text{Projected} = \text{Spent Today} + \sum \text{Pending Prepared Locks} + \text{New Amount}$$ If projected spend exceeds the daily limit, the transaction is rejected (400 Bad Request). -
Zero-Drift Micro-USDC Integer Arithmetic: Integer amounts (
u64micro-USDC: $1.00 = 1,000,000 micros) eliminate IEEE-754 floating-point rounding errors in cryptographic audit chains.
-
24-Hour Rolling Spend Limits: Tracked in
The router applies these controls:
- boot readiness gate
- auth brute-force limiter
- security headers
- request ID injection
- rate-limit headers
- tracing spans
- deprecation middleware
- request timeout
- response compression
- CORS
Security headers are injected by server-rs/src/middleware/security_headers.rs:
- Content-Security-Policy
- Strict-Transport-Security
- X-Content-Type-Options
- X-Frame-Options
- Referrer-Policy
server-rs/src/middleware/cors.rs enforces an allow-list from ALLOWED_ORIGINS.
Behavior:
ALLOWED_ORIGINS=*enables wildcard troubleshooting mode and disables credentials.- A comma-separated list enables those exact origins with credentials.
- An empty value falls back to local development origins:
localhost/127.0.0.1on ports5173and3000, plustauri://localhost. - Private Network Access (PNA): Both
cors.rsandsecurity_headers.rsinjectAccess-Control-Allow-Private-Network: trueto prevent browser pre-flight blocks when web origins communicate with local development daemon loopback addresses (127.0.0.1/localhost).
Data Loss Prevention is enforced symmetrically across both the Rust backend and the frontend runtime:
-
Deterministic Regex Interceptor: Before any user prompt or command string is processed, routed to an agent, or sent to a local/cloud model, it passes through
scan_and_redact_secrets(). -
Target Patterns Scrubbed:
- OpenAI API keys:
sk-[a-zA-Z0-9_-]{20,}$\to$ [REDACTED_AI_KEY] - Anthropic API keys:
sk-ant-[a-zA-Z0-9_-]{20,}$\to$ [REDACTED_AI_KEY] - Google Gemini / Cloud keys:
AIzaSy[a-zA-Z0-9_-]{33}$\to$ [REDACTED_AI_KEY] - GitHub personal access tokens:
gh[pousr]_[a-zA-Z0-9]{36,}$\to$ [REDACTED_GITHUB_TOKEN] - Bearer tokens:
Bearer\s+[A-Za-z0-9\-_.~+/]+=*$\to$ Bearer [REDACTED_BEARER_TOKEN] - RSA / EC Private Keys:
-----BEGIN [A-Z ]*PRIVATE KEY-----$\to$ [REDACTED_PRIVATE_KEY]
- OpenAI API keys:
-
DOM Context DLP: Scraped active DOM state summarized by the Browser Sentinel (
summarize_active_dom()) is sanitized through the same DLP shield before being presented to the in-browser neural specialist, preventing inadvertent token exfiltration from rendered forms or debug panels.
Secret redaction is centralized through server-rs/src/secret_redactor.rs and used by AppState broadcast helpers before log/event publication.
Sensitive environment keys include:
NEURAL_TOKEN- cloud provider API keys
- other provider and credential-style values recognized by the redactor
Logs and telemetry should never intentionally include raw token values.
server-rs/src/security/scanner.rs implements command/script risk detection. It checks:
- known loaded secrets
- common API key formats
- raw secret export patterns
- command concatenation such as
;,&&, and|| - pipes and redirection
- command substitution
- optional aggressive checks when
AGGRESSIVE_SECURITY=true
The scanner is intentionally conservative and can flag valid complex shell commands. Risky results should be treated as requiring review rather than automatically safe execution.
For legacy and external execution tools, execution/tadpole_mcp_server.py enforces additional sandboxing boundaries to mitigate Remote Code Execution (RCE):
- Argument-Split Spawning: Spawns processes using
asyncio.create_subprocess_execandshlex.split, completely avoiding shell interpretation (shell=Falseequivalent). - Resource Boundaries: Implements Unix limits via
setrlimiton CPU runtime (30s maximum execution time) and virtual memory address space (256MB bounds), preventing resource exhaustion. - Input Schema Enforcements: Directs all inputs through strict type-safe schema checks before command assembly.
Security state is owned by SecurityHub in server-rs/src/state/hubs/sec.rs and assembled through AppState.
The security hub includes:
- Merkle audit trail
- budget guard
- shell scanner
- secret redactor
- system monitor
- permission policy
- deploy token
Oversight/security API routes are exposed under /v1/oversight/security/*.
PRIVACY_MODE=true steers runtime behavior toward local-only provider use. The privacy guard is started from startup::spawn_background_tasks.
Local insecure model-provider HTTP can be allowed with:
TADPOLE_ALLOW_LOCAL_HTTP=trueBefore deploying beyond local development:
- Set a strong
NEURAL_TOKENorNEURAL_ENGINE_ACCESS_TOKEN. - Set
ALLOWED_ORIGINSexplicitly for deployed or shared environments. - Validate that
.envis excluded from source control. - Run frontend and Rust test suites.
- Confirm protected endpoints reject missing and invalid bearer tokens.
- Confirm the dashboard stores and sends the same token configured for the engine.
- Review feature gates before enabling
vector-memoryorneural-audio.
| Area | Expected behavior | Suggested check |
|---|---|---|
| Public health | GET /v1/engine/health succeeds without auth |
call endpoint without Authorization |
| Protected API | /v1/agents rejects missing auth |
call endpoint without token and expect 401 |
| Invalid token | protected routes reject wrong bearer token | call with Authorization: Bearer wrong and expect 401 |
| Valid token | protected routes accept configured token | call with .env token and expect non-401 |
| WebSocket token | protected WS flows can use bearer.<token> subprotocol when needed |
verify browser upgrade path when route is protected |
| CORS allow-list | configured origins are allowed | set ALLOWED_ORIGINS and verify preflight |
| CORS wildcard | ALLOWED_ORIGINS=* disables credentials |
verify wildcard response has no credential support |
| Vector memory disabled | memory routes return 501 without feature |
run engine without vector-memory and call memory route |
| Vector memory enabled | memory routes become available | run engine with --features vector-memory |