Security Architecture

Tier 2 | Deep technical documentation for security implementation Hub: README.md | Full Architecture: ARCHITECTURE.md


Overview

Security-first design with 7 defense layers:

  1. Input Validation - Zod schemas at all boundaries
  2. Secrets Vault - Never expose API keys or tokens
  3. Rate Limiting - Token bucket per tool
  4. Memory Bounds - Context pruning, history caps
  5. Path Safety - Normalized paths, directory jails
  6. Timeout Protection - TimeoutGuard for async operations
  7. Byzantine Detection - Weighted voting with pattern detection

Authentication & Access Control

Nexus-agents uses a secure-by-default approach appropriate for its primary use case as a local CLI/MCP tool:

  • MCP mode (default): Communicates over stdio with the parent process only — no network listener, no external access possible. Authentication is not required because only the local process can communicate with the server.
  • REST API mode (opt-in): When enabled via the YAML config api.enabled: true, an API key is auto-generated and stored at ~/.nexus-agents/auth/rest-api-key with restrictive file permissions (0600). All REST endpoints require this key via the Authorization header.
EnvironmentAuth Needed?Notes
Local MCP (stdio)NoOnly the parent process can reach the server
Local REST APIAutoAPI key auto-generated on first start
Network-exposedYesSet NEXUS_AUTH_ENABLED=true
Production deploymentYesEnable auth and use HTTPS

Token-Based Authentication (Issue #739)

For network-exposed deployments, nexus-agents provides token-based authentication via the AuthHandler middleware (src/mcp/middleware/auth-handler.ts).

Token management CLI commands:

nexus-agents auth init          # Generate new auth token
nexus-agents auth show          # Show token status (file path, permissions)
nexus-agents auth rotate        # Rotate token (invalidate old, generate new)
nexus-agents auth init --force  # Regenerate token (overwrite existing)

Security properties:

  • Tokens are 64-character hex strings (32 bytes of crypto.randomBytes)
  • Stored at ~/.nexus-agents/auth/server-token with 0600 permissions (owner read/write only)
  • Directory created with 0700 permissions
  • Timing-safe comparison (crypto.timingSafeEqual) prevents timing attacks
  • Token shown only once on generation (not recoverable — rotate if lost)

Enabling authentication:

# nexus-agents.yaml
security:
  auth:
    enabled: true
    method: token # 'token' (default) or 'oauth2' (future)
    tokenHeader: Authorization # Header name for Bearer token
    tokenFile: ~/.nexus-agents/auth/server-token # Token storage path

Or via environment variables:

export NEXUS_AUTH_ENABLED=true
nexus-agents --mode=server

Client usage:

# Include token in Authorization header
curl -H "Authorization: Bearer $(cat ~/.nexus-agents/auth/server-token)" \
  http://localhost:3000/api/orchestrate

Threat Model

ThreatVectorMitigationStatus
Prompt InjectionMalicious promptsInput/output tagging, structured output
SSRFOutbound HTTP callsURL allowlist, private IP blocking
Path TraversalMalicious file pathsPath normalization, directory jail
ReDoSMalicious regexStatic patterns only, no user RegExp
MCP SDK ReDoSCVE-2026-0621TimeoutGuard, URI validation
Secrets ExposureLogs, errorsSecrets vault, sanitization
Token ExhaustionUnbounded contextMemory caps, pruning
InjectionMalformed promptsInput validation, Zod schemas
Byzantine FailuresMalicious agentsWeighted voting with Byzantine detection

Reference: OWASP LLM Top 10 (LLM01: Prompt Injection)


MCP Middleware Security

Every MCP tool invocation passes through a hardened middleware pipeline:

LayerProtection
AuthenticationBearer token validation with timing-safe compare
CORSStrict origin checking for HTTP transports
Security HeadersX-Content-Type-Options, X-Frame-Options, CSP
Body Size LimitsConfigurable max request size (default 1 MB)
Input ValidationSize limits on tool arguments, Zod validation
Policy FirewallAllowlist/denylist rules per tool with enforcement
Rate LimitingToken bucket per tool (configurable requests/min)
Output SanitizationSecret pattern redaction (keys, tokens, passwords)
Audit LoggingSIEM-compatible JSON-L events for tool invocations

Configuration

security:
  policy:
    policyMode: enforce # enforce | warn
    defaultMode: read-only # read-only | read-write

  rateLimit:
    enabled: true
    requestsPerMinute: 60

  audit:
    enabled: true
    logDir: ~/.nexus-agents/audit
    minSeverity: info # info | warning | critical
    enableHashChain: false # Tamper-evident log chain
    maxFileSizeBytes: 10485760
    maxFiles: 10

Sandbox Execution

All agent-executed code runs through the sandbox system.

Execution Modes

ModeDescriptionSecurity LevelUse Case
noneNo sandboxing (development only)NoneLocal dev, debugging
policyCommand allowlist enforcementMediumStandard operation
containerFull Docker isolationHighProduction, untrusted input

Docker Security (Container Mode)

docker run \
  --cap-drop=ALL \           # Drop all Linux capabilities
  --read-only \              # Read-only root filesystem
  --network=none \           # No network access
  --user=node \              # Non-root user
  --memory=512m \            # Memory limit
  --cpus=2 \                 # CPU limit
  --pids-limit=10 \          # Process limit
  --security-opt=no-new-privileges

Command Classification

CategoryCommandsAction
Allowedpnpm, npm, git, gh, node, npx, tsc, eslint, vitestExecute in sandbox
Deniedrm, curl, wget, ssh, sudo, kill, chmod, dd, mkfsBlock immediately
Requires Approvaldocker, kubectl, aws, gcloudUser confirmation

Resource Limits

ResourceLimitRationale
Memory512 MBPrevent memory exhaustion
CPU2 coresPrevent CPU monopolization
Timeout5 minutesPrevent hung processes
Processes10 maxPrevent fork bombs
Disk writeRead-onlyPrevent persistent changes
NetworkNonePrevent data exfiltration

Environment Sanitization

Variables blocked from execution context:

const BLOCKED_PREFIXES = [
  'API_',
  'TOKEN_',
  'SECRET_',
  'KEY_',
  'PASSWORD_',
  'CREDENTIAL_',
  'AWS_',
  'AZURE_',
  'GCP_',
  'ANTHROPIC_',
  'OPENAI_',
  'GOOGLE_AI_',
];

function sanitizeEnv(env: Record<string, string>): Record<string, string> {
  return Object.fromEntries(
    Object.entries(env).filter(
      ([key]) => !BLOCKED_PREFIXES.some((prefix) => key.startsWith(prefix))
    )
  );
}

Secrets Vault Pattern

class SecretsVault {
  private readonly secrets: Map<string, string>;

  get(key: string): string | undefined {
    // Audit log access
    return this.secrets.get(key);
  }

  // Sanitize before any output
  sanitize(text: string): string {
    for (const secret of this.secrets.values()) {
      text = text.replaceAll(secret, '[REDACTED]');
    }
    return text;
  }
}

Usage Rules

  1. Never log secrets - Use sanitize() before any logging
  2. Never return secrets - Sanitize all tool outputs
  3. Audit access - Log when secrets are accessed
  4. Rotate regularly - Support key rotation without restart

Input Validation Pipeline

const validateInput = (input: unknown): Result<ValidInput, ValidationError> => {
  // 1. Schema validation (Zod)
  const parsed = InputSchema.safeParse(input);
  if (!parsed.success) return { ok: false, error: parsed.error };

  // 2. Business rule validation
  if (parsed.data.value < 0) {
    return { ok: false, error: new ValidationError('Value must be positive') };
  }

  // 3. Security checks (path traversal, injection, etc.)
  const sanitized = sanitizeInput(parsed.data);

  return { ok: true, value: sanitized };
};

Path Traversal Prevention

function validatePath(userPath: string, allowedRoot: string): Result<string, SecurityError> {
  const resolved = path.resolve(allowedRoot, userPath);
  if (!resolved.startsWith(allowedRoot)) {
    return { ok: false, error: new SecurityError('Path traversal detected') };
  }
  return { ok: true, value: resolved };
}

Directory Jail

All file operations are restricted to:

  • Current working directory
  • Explicitly allowed paths in config
  • Temporary directories with cleanup

ReDoS Prevention

// NEVER do this - user-provided regex
const pattern = new RegExp(userInput); // DANGEROUS!

// ALWAYS do this - static patterns only
const VALID_PATTERN = /^[a-zA-Z0-9_-]+$/; // Static, safe pattern

// Validate against known-safe patterns
function validateIdentifier(input: string): boolean {
  return VALID_PATTERN.test(input);
}

CVE-2026-0621 Mitigation

TimeoutGuard for all async operations:

const result = await TimeoutGuard.execute(async () => await mcpTool.execute(args), {
  timeout: 30000,
  name: 'mcp-tool-call',
});

Rate Limiting

Token bucket per tool:

const rateLimiter = new TokenBucket({
  capacity: 100, // Max burst
  refillRate: 10, // Tokens per second
});

async function executeWithRateLimit<T>(fn: () => Promise<T>, cost: number = 1): Promise<T> {
  if (!rateLimiter.consume(cost)) {
    throw new RateLimitError('Rate limit exceeded');
  }
  return fn();
}

Per-Tool Limits

Tool CategoryRequests/minRationale
Read operations120Low risk, high frequency
Write operations60Higher risk, audit trail
Execute commands30Highest risk, full audit
External API60Provider limits

Sanitization Pipeline

All output passes through sanitization:

// Standard sanitization
const sanitized = logger.sanitize(text);
// API keys, tokens, passwords -> [REDACTED]

// Patterns matched
const REDACT_PATTERNS = [
  /sk-[a-zA-Z0-9]{48}/g, // Anthropic API keys
  /sk-[a-zA-Z0-9-_]{43}/g, // OpenAI API keys
  /ghp_[a-zA-Z0-9]{36}/g, // GitHub tokens
  /password["']?\s*[:=]\s*["']?[^"'\s]+/gi, // Password values
];

Security Audit Logging

Audit events are written as SIEM-compatible JSON-L to ~/.nexus-agents/audit/ (configurable).

Event Types

EventSeverityTrigger
tool_invocationinfoEvery tool call (success/failure)
policy_decisionwarningPolicy firewall deny
rate_limit_violationwarningRate limit exceeded
system_startup/shutdowninfoServer lifecycle events

Enabling Audit Logging

security:
  audit:
    enabled: true
    minSeverity: info
    enableHashChain: true # Optional tamper-evident chain

Each event includes: timestamp, actor, tool name, request ID, duration, and outcome. With enableHashChain: true, events include a SHA-256 hash chain for tamper detection.


Configuration

security:
  sandbox:
    mode: policy # none | policy | container
    fallbackMode: none # Fallback if container unavailable
    resourceLimits:
      memory: 512m
      cpu: 2
      timeout: 300s
      maxProcesses: 10

  allowedPaths: [./] # Directory jail

  policy:
    policyMode: enforce # enforce | warn
    defaultMode: read-only # read-only | read-write

  rateLimit:
    enabled: true
    requestsPerMinute: 60

  audit:
    enabled: false # Set to true for structured audit logging
    logDir: ~/.nexus-agents/audit
    minSeverity: info # info | warning | critical
    enableHashChain: false # Tamper-evident hash chain
    maxFileSizeBytes: 10485760 # 10 MB per log file
    maxFiles: 10 # Log rotation file count

Security Checklist

Before any code change:

  • No secrets in code, logs, or outputs
  • Input validation at all boundaries
  • Path traversal prevention on file ops
  • No user-provided RegExp (use static patterns)
  • Rate limiting on public interfaces
  • Memory bounds on collections
  • Timeout on external calls
  • Sanitization on all outputs

Agent-SafetyBench Evaluation

Comprehensive safety category taxonomy for agent evaluation (arXiv:2412.14470).

Safety Categories

CategoryRisk LevelDescription
harm_physicalCriticalActions causing physical harm
harm_emotionalHighPsychological or emotional harm
harm_financialHighFinancial loss or fraud
deceptionHighMisleading or false information
biasMediumDiscriminatory outputs
privacyHighPrivacy violations, data exposure
manipulationHighSocial engineering, coercion
instruction_safetyCriticalJailbreak, prompt injection
robustnessMediumAdversarial input resilience
risk_awarenessMediumAppropriate caution and escalation

Expected Outcomes

OutcomeDescription
refuseDecline harmful request
cautionProceed with warnings
clarifyRequest more information
escalateElevate to human review
proceedSafe to execute
detectIdentify and report attack attempt

Usage

import { SAFETY_CATEGORIES, getSafetyTaxonomySummary } from 'nexus-agents';

// Get all categories
for (const category of SAFETY_CATEGORIES) {
  console.log(`${category.id}: ${category.defaultRiskLevel}`);
}

// Get summary statistics
const summary = getSafetyTaxonomySummary();
// { totalCategories: 10, totalCriteria: 42, ... }

Source Files

FilePurpose
src/mcp/middleware/auth-handler.tsToken-based authentication
src/mcp/middleware/secure-handler.tsTool-level security wrapper
src/mcp/middleware/request-context.tsRequest tracking and auth
src/mcp/middleware/rate-limiter.tsRate limiting
src/security/sandbox/sandbox-manager.tsSandbox orchestration
src/security/sandbox/docker-sandbox-executor.tsContainer isolation
src/security/input-sanitizer.tsInput validation
src/security/output-sanitizer.tsOutput sanitization / secrets
src/security/trust-classifier.tsTrust tier classification
src/security/policy-gate.tsPolicy enforcement
src/security/corroboration-validator.tsAction corroboration checks
src/security/reputation-model.tsAgent reputation scoring
src/security/audit-trail.tsSecurity logging
src/security/firewall/Firewall pipeline
src/security/safety-bench/SafetyBench evaluation
src/security/safety-bench/safety-categories.tsCategory taxonomy
src/security/safety-bench/safety-enums.tsRisk levels, outcomes
src/security/safety-bench/safety-schemas.tsValidation schemas

Penetration Testing

113 security tests covering:

  • Container escape prevention
  • Capability restrictions
  • Network isolation
  • Filesystem isolation
  • Privilege escalation prevention
  • Command injection prevention
  • Environment variable sanitization
  • CVE regression tests

Run with:

pnpm test src/security/sandbox-pentest.test.ts