Overview
TaurusX is designed with security as a first-class architectural concern — not an add-on. The platform uses a layered defence model: each surface enforces its own security controls, and all controls reinforce each other. No single point of failure can compromise the system.
The Phase 2 security baseline covers ten areas: web hardening, API hardening, mobile security, OS Chat input safety, Meta-Agent limits, Governance enforcement, Routing Engine isolation, Preferences encryption, Terminal/CLI hardening, and developer guidelines.
security@taurusx.app. Do not open public issues for security findings.Web Security Hardening
All TaurusX web surfaces (OS, Guardian Console, public site) enforce the following controls on every response:
| Control | Implementation | Value |
|---|---|---|
| Content-Security-Policy | Next.js Middleware | default-src 'self'; frame-ancestors 'none'; form-action 'self' |
| HSTS | Middleware + proxy | max-age=63072000; includeSubDomains; preload |
| X-Frame-Options | Middleware | DENY |
| X-Content-Type-Options | Middleware | nosniff |
| Referrer-Policy | Middleware | strict-origin-when-cross-origin |
| Permissions-Policy | Middleware | camera=(), microphone=(), geolocation=() |
CSRF Protection
TaurusX uses a double-layer CSRF defence. For JSON API calls, Origin/Referer headers are validated against the allowed-host list. For form-based submissions, the Double-Submit Cookie pattern is enforced: the tx_csrf cookie must match the X-CSRF-Token header. Bearer token and API-key callers are exempt (not browser CSRF targets).
XSS Prevention
All user-generated content (personal notes, profile fields, preferences) passes through sanitize.ts before storage and before rendering. The sanitizer strips dangerous HTML tags, event handlers, and javascript: / data: URIs. AI-generated Markdown is sanitized before rendering to prevent injected scripts.
Session Security
| Property | Value |
|---|---|
| Cookie name | tx_session (OS), tx_admin_session (Guardian) |
| HttpOnly | true — not accessible via JavaScript |
| SameSite | lax (OS session), strict (admin session) |
| Secure flag | true in production — HTTPS only |
| Session TTL | 7 days (auto-renew on activity) |
| Re-auth window | 15 minutes for sensitive operations |
API Hardening
Authentication & Authorization
Every API endpoint is protected by one or more of: session cookie, Bearer token, or API key validation. All three are checked and validated against the database — not just verified for presence. The apiGuard() helper combines auth, role checks, IDOR validation, rate limiting, and input validation in a single composable call.
Input Validation
All JSON bodies, query parameters, and path parameters are validated against Zod schemas before processing. Validation errors return structured 400 responses with per-field issue details. Raw validation errors never reach production responses.
Rate Limiting
| Tier | Scope | Limit |
|---|---|---|
| Edge (middleware) | Per IP | 60 req/min (default), 20 req/min (sensitive) |
| Postgres-backed | Per user / workspace / IP | Plan-tiered (60–10,000 req/5 min) |
| Zero-Trust | Per email (auth flows) | Escalating cooldown on failures |
| CLI revocation | Per IP | 10 req/min |
Sensitive endpoints — /api/security, /api/meta-agent,/api/governance, /api/preferences,/api/billing, /api/agents,/api/workflows — are on the 20 req/min strict tier.
Error Responses
Production API errors return a sanitized envelope: error (code),message (user-safe text). No stack traces, no file paths, no SQL details, no internal class names. Development environments include a dev field with the full error for debugging.
Safe Logging
All server-side logs pass through safeLog.ts. The logger automatically redacts Bearer tokens, session cookies, API keys, JWTs, email addresses, phone numbers, credit card numbers, and file paths before writing to stdout. Strings are truncated at 2,000 characters.
Mobile App Security
The TaurusX mobile app (iOS / Android) applies the following security measures:
| Control | Implementation |
|---|---|
| Sensitive data storage | expo-secure-store (AES-256, backed by Keychain on iOS, Keystore on Android) |
| Token storage | SecureStore — never written to AsyncStorage or local JSON |
| TLS enforcement | All network calls via secureFetch — non-HTTPS rejected in production |
| Host allowlist | secureFetch validates hostname against registered TaurusX hosts |
| Request timeout | 30 seconds — prevents hanging requests |
| Deep-link validation | deepLinkGuard.ts — validates scheme, path, params before processing |
| Blocked deep-link params | token, access_token, password, session, api_key |
/settings/profile/security,/settings/billing, /admin) are blocked regardless of authentication status. Those paths require intentional in-app navigation.OS Chat & Desktop Hardening
The OS Chat Screen and Desktop Continuum apply a security pipeline to every message before it reaches the Routing Engine and before any response is rendered:
| Stage | What it does |
|---|---|
| Input sanitization | Strips dangerous HTML tags and event handlers from user messages |
| Link sanitization | Validates all Markdown links — unsafe URLs are replaced with # |
| Prompt injection detection | Pattern-matches against known injection phrases; replaces with safety placeholder |
| Response sanitization | sanitizeRenderedHtml() on all assistant output before display |
| Session re-auth check | High-risk actions (delete account, billing, key rotation) require re-auth within 15 min |
Prompt injection detection looks for patterns such as "ignore previous instructions", "DAN mode", injected system prompts via code fences, and role-reset instructions. Detected patterns are neutralized — the user message is still processed with the injected content replaced by a safety placeholder.
Meta-Agent Safety Limits
| Limit | Value | Why |
|---|---|---|
| MAX_RECURSION_DEPTH | 5 | Prevents infinite delegation chains |
| MAX_PLAN_STEPS | 20 | Caps plan complexity and execution time |
| MAX_TOOL_CALLS_PER_RUN | 50 | Hard stops runaway tool loops |
| MAX_CONTEXT_TOKENS | 32,000 | Prevents context poisoning attacks |
| PLAN_REVIEW_THRESHOLD | 5 steps | Plans with ≥ 5 steps require user confirmation |
The meta-agent action registry defines exactly which actions the agent may execute. Any action not in the registry is rejected. Actions are classified by category (read / write / external / system) and risk level (low / medium / high / critical).
Governance Engine
The Governance Engine evaluates every high-impact action before execution. Actions are classified by risk, reversibility, and external effect.
| Risk Level | Examples | Default Behaviour |
|---|---|---|
| Low | Update profile, store memory | Allowed automatically |
| Medium | Trigger workflow, update workspace | Allowed; audit-logged |
| High | Delete agent, execute integration, change role | Requires explicit confirmation |
| Critical | Delete account, cancel billing, override governance | Requires confirmation + re-auth |
Governance rules are validated on creation using a strict Zod schema. Invalid configurations are rejected before saving — you cannot create a rule that would deny all low-risk actions or has a malformed condition value. All governance decisions (allow, deny, require-approval) are written to the immutable audit log.
User boundaries from Personal Preferences are enforced by the Governance Engine. Topics marked as off-limits are checked against every proposed action and response. Boundary violations are denied and logged.
Routing Engine Security
| Control | Implementation |
|---|---|
| Session isolation | sessionId → userId binding; cross-user context leakage blocked |
| Input sanitization | sanitizeMarkdown() on every message before dispatch |
| Injection detection | detectPromptInjection() on every message; patterns neutralized |
| History sanitization | All conversation history entries sanitized on each request |
| Metadata stripping | Only primitive values allowed in routing metadata |
| Message length cap | 32,000 characters — oversized messages rejected with 400 |
| History length cap | 200 entries — older history truncated automatically |
Session ownership is validated on every routing request. If a session ID is presented for a different user ID than was registered at session creation, the request is rejected with a hard failure (not a safe fallback).
Preferences & Identity Security
Personal Preferences — notes, boundaries, tone settings, accessibility flags — are stored using expo-secure-store on mobile (AES-256 hardware-backed) and in the encrypted session context on web. They are never stored in plaintext local storage or in unencrypted cookies.
Boundary enforcement runs on every AI response and action across all surfaces (web, mobile, terminal, meta-agent, voice). The boundary check happens inboundaryEnforcer.ts and is called before any content is sent to the user or any action is executed.
| Surface | Boundary enforcement |
|---|---|
| Web / OS Chat | checkBoundaries() before rendering each response |
| Mobile | checkBoundaries() on every assistant message |
| Voice / Hands-Free | containsVoiceUnsafeContent() + topic check before TTS |
| Meta-Agent | actionViolatesBoundaries() on each plan step |
| Terminal / CLI | tx ask responses are checked before display |
Terminal & CLI Security
| Control | Implementation |
|---|---|
| Device binding | Access tokens include deviceId; validated on every request |
| Token expiry | Access token: 1 hour. Refresh token: 30 days. Hard expiry enforced. |
| Replay protection | Signed requests carry X-TX-Timestamp + X-TX-Nonce; nonces stored + rejected on replay |
| Timestamp tolerance | 5-minute window — requests outside this are rejected |
| Nonce TTL | 10 minutes — nonces pruned after expiry |
| Device revocation | POST /api/auth/cli/revoke — revokes any device session; audit-logged |
| Privilege checks | Every CLI command validates role against session; no elevation possible |
| Rate limiting | CLI revocation: 10 req/min per IP; CLI authorize: subject to auth rate limits |
The CLI credential file (~/.taurusx/credentials.json) is written with mode 0o600 (owner-only read/write). The preferred storage is the OS keychain via keytar.
Developer Security Guidelines
Required for every API route
- Use
apiGuard()or manually callgetSession()+hasRole() - Validate all inputs with
validateBody()/validateQuery()and a Zod schema - Use
safeError()/safeInternalError()in all catch blocks — neverNextResponse.json({ error: err.message }) - Log with
safeLog— neverconsole.logfor server events - Check resource ownership for user-scoped routes (IDOR prevention)
- Add rate limiting via
checkRateLimitPg()for mutating endpoints
Never do these
- Log tokens, passwords, session IDs, or API keys
- Return raw
error.messageor stack traces in production API responses - Store tokens in
AsyncStorage,localStorage, or cookies withoutHttpOnly - Render user-provided content as HTML without passing it through
sanitize.ts - Hard-code secrets, API keys, or credentials in source files
- Skip governance checks for meta-agent actions that affect external systems
- Accept deep-link parameters named
token,session, orapi_key
Security modules reference
| Module | Purpose |
|---|---|
| lib/security/apiGuard.ts | Composable API security gate (auth + role + rate limit + validation) |
| lib/security/csrf.ts | CSRF token generation and validation |
| lib/security/sanitize.ts | XSS sanitization for all user content |
| lib/security/safeError.ts | Production-safe error responses |
| lib/security/safeLog.ts | Secrets-redacting structured logger |
| lib/security/routingGuard.ts | Routing Engine input sanitization + context isolation |
| lib/security/osChatGuard.ts | OS Chat message sanitization + injection detection |
| lib/security/boundaryEnforcer.ts | User boundary enforcement across all surfaces |
| services/metaAgentGuard.ts | Meta-Agent depth limits, plan validation, action registry |
| services/governanceGuard.ts | Governance rule validation, action classification, decisions |
| app/lib/security/networkGuard.ts | Mobile TLS enforcement, safe fetch wrapper |
| app/lib/security/deepLinkGuard.ts | Mobile deep-link validation and injection prevention |
| tx/src/auth/replayProtection.ts | CLI token replay protection, device binding, expiry checks |