veritas-kanban/docs/security.md
Brad Groux 522162ae89
test: add v5 permission coverage manifest gate
## Summary

- adds a v5 permission coverage manifest with classifications, required permissions, denial reasons, and review justifications across REST, WebSocket, CLI, MCP, workflow, transition hook, command palette, and background job surfaces
- adds a Node-based coverage checker that fails when tracked surfaces are missing from the manifest or when REST route prefixes drift from the shared permission map
- wires the checker into CI and documents the manifest gate in the security guide

Closes #420.

## Verification

- `node scripts/check-permission-coverage.mjs`
- `./node_modules/.bin/prettier --check package.json .github/workflows/ci.yml scripts/check-permission-coverage.mjs docs/security/permission-coverage.json docs/security.md`
- `git diff --check`
- `pnpm lint:budget`
- `pnpm build`
- `pnpm audit --prod --audit-level=high` (passes high gate; 3 existing moderate findings)
- GitHub Actions: Build, Lint & Type Check, Security Audit, Workspace Unit Tests
2026-05-31 05:02:26 -05:00

12 KiB

Veritas Kanban Server - Security Guide

Overview

The Veritas Kanban server includes a flexible authentication and authorization system to protect API endpoints and WebSocket connections from unauthorized access.

Quick Start

Development (Localhost Bypass)

For local development, enable localhost bypass:

# .env
VERITAS_AUTH_ENABLED=true
VERITAS_AUTH_LOCALHOST_BYPASS=true

This allows unauthenticated requests from localhost/127.0.0.1 while still requiring auth for remote connections.

Production

For production, configure API keys:

# .env
VERITAS_AUTH_ENABLED=true
VERITAS_AUTH_LOCALHOST_BYPASS=false
VERITAS_ADMIN_KEY=your-secure-admin-key
VERITAS_API_KEYS=agent1:key1:agent,dashboard:key2:read-only

Authentication Methods

Clients can authenticate using any of these methods:

curl -H "Authorization: Bearer your-api-key" \
  http://localhost:3001/api/tasks

2. X-API-Key Header

curl -H "X-API-Key: your-api-key" \
  http://localhost:3001/api/tasks

3. Query Parameter (WebSocket)

const ws = new WebSocket('ws://localhost:3001/ws?api_key=your-api-key');

Roles and Permissions

v5 planning note: the current role model is intentionally small. The planned multi-user model expands this into workspace-scoped owner, admin, member, reviewer, read-only, and agent roles with scoped agent tokens. See v5 Identity, Workspace, and RBAC Model.

Role Read Write Admin Actions
admin ✅ ✅ ✅
agent ✅ ✅ ❌
read-only ✅ ❌ ❌

Role Details

  • admin: Full access to all endpoints including sensitive operations
  • agent: Can read/write tasks, run agents, manage worktrees. Intended for AI agents like OpenClaw
  • read-only: Can only perform GET requests. Suitable for dashboards and monitoring

v5 Auth Context

Authenticated REST requests and WebSocket connections now carry a shared auth context for the v5 RBAC migration:

Field Description
role Current compatibility role: admin, agent, read-only
userId Local fallback user ID until persisted users are enforced
workspaceId Local fallback workspace ID until workspace scoping lands
actorType user, agent, service, or localhost-bypass
authMethod disabled, session, api-key, or localhost-bypass
tokenName API key name when authenticated with a configured key
permissions Role-derived permission list used by new route guards

New v5 endpoints should prefer explicit permission guards over broad role checks. Legacy role guards remain supported while route coverage is migrated.

The v5 authority surface is tracked in docs/security/permission-coverage.json. Run node scripts/check-permission-coverage.mjs to fail when a REST route prefix, WebSocket event, CLI command, MCP tool, workflow step/action type, command palette action, or tracked background job is added without a permission classification.

Configuration Reference

Environment Variables

Variable Default Description
VERITAS_AUTH_ENABLED true Enable/disable authentication
VERITAS_AUTH_LOCALHOST_BYPASS false Allow unauthenticated localhost requests
VERITAS_ADMIN_KEY (none) Admin API key with full access
VERITAS_API_KEYS (none) Comma-separated API keys (format: name:key:role)

API Key Format

name:key:role,name2:key2:role2

Example:

veritas:vk_abc123xyz:agent,dashboard:vk_def456uvw:read-only

Generating API Keys

Using OpenSSL

# Generate a random 32-character key
openssl rand -base64 32

Using the Built-in Function

import { generateApiKey } from './middleware/auth.js';
const key = generateApiKey('vk'); // e.g., vk_AbCdEf123...

API Endpoints

Auth Status (Unauthenticated)

Check the current authentication configuration:

curl http://localhost:3001/api/auth/status

Response:

{
  "enabled": true,
  "localhostBypass": false,
  "configuredKeys": 2,
  "hasAdminKey": true
}

Health Check (Unauthenticated)

curl http://localhost:3001/health

WebSocket Authentication

WebSocket connections are authenticated on connect:

// With API key
const ws = new WebSocket('ws://localhost:3001/ws?api_key=your-key');

ws.onclose = (event) => {
  if (event.code === 4001) {
    console.error('Authentication failed:', event.reason);
  }
};

WebSocket Close Codes

Code Meaning
1000 Normal close
4001 Authentication required/failed

Error Responses

401 Unauthorized

{
  "error": "Authentication required",
  "code": "AUTH_REQUIRED",
  "hint": "Provide API key via Authorization header (Bearer <key>), X-API-Key header, or api_key query parameter"
}

403 Forbidden

{
  "error": "Write access denied",
  "code": "WRITE_FORBIDDEN",
  "hint": "Your API key has read-only access"
}

Security Best Practices

  1. Never commit API keys - Use environment variables or .env files (add to .gitignore)

  2. Rotate keys regularly - Update API keys periodically, especially if compromised

  3. Use HTTPS in production - API keys are transmitted in headers/URLs

  4. Principle of least privilege - Use read-only for dashboards, agent for automation

  5. Monitor access - The server logs connection attempts with role information

Migrating from No Auth

If you're upgrading from an earlier version without authentication:

  1. Before upgrading: Document all clients that access the API

  2. During upgrade:

    • Start with VERITAS_AUTH_LOCALHOST_BYPASS=true for smooth transition
    • Generate API keys for each client
    • Update clients to include authentication headers
  3. After testing: Disable localhost bypass for production

Troubleshooting

"Authentication required" for localhost

Check that VERITAS_AUTH_LOCALHOST_BYPASS=true is set, or provide an API key.

"Invalid API key"

  • Verify the key matches exactly (no extra spaces)
  • Check that the key is in the VERITAS_API_KEYS or VERITAS_ADMIN_KEY variable
  • Ensure the format is correct: name:key:role

WebSocket immediately closes

  • Check browser console for the close reason
  • Ensure the API key is passed as a query parameter: ?api_key=...

Architecture

┌─────────────────────────────────────────────────────────────┐
│                       Request Flow                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Client Request                                             │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────────┐                                          │
│  │ CORS/JSON    │ (express middleware)                     │
│  └──────────────┘                                          │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────────┐   ┌───────────────────────┐              │
│  │ /health      │──▶│ Bypass auth           │              │
│  │ /api/auth/*  │   │ (unauthenticated)     │              │
│  └──────────────┘   └───────────────────────┘              │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────────┐                                          │
│  │ authenticate │ (middleware/auth.ts)                     │
│  │              │                                          │
│  │ - Check auth │                                          │
│  │   enabled    │                                          │
│  │ - Localhost  │                                          │
│  │   bypass?    │                                          │
│  │ - Validate   │                                          │
│  │   API key    │                                          │
│  └──────────────┘                                          │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────────┐                                          │
│  │ Route Handler│ (req.auth available)                     │
│  └──────────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Changelog

  • v3.3.0 (2026-02-15): Task intelligence security hardening
    • Crash-recovery checkpointing with auto-sanitization of 20+ secret patterns plus regex value detection
    • XSS prevention in observational memory via sanitizeCommentText()
    • DFS cycle detection in task dependencies prevents infinite loop attacks
    • Input sanitization on agent filter (trim + 100 char cap)
    • Zod validation on all dependency and checkpoint routes
  • v3.0.0 (2026-02-09): Workflow engine security
    • ReDoS protection on regex acceptance criteria
    • Expression injection prevention in template evaluator
    • Parallel DoS limits (max 50 concurrent sub-steps)
    • Gate approval authentication and permission checks
    • RBAC with ACL files for workflow access control
    • Audit logging of all workflow changes
  • v2.0.0 (2026-02-06): Multi-agent security
    • Agent permission levels (Intern/Specialist/Lead) with enforcement
    • Agent registry with heartbeat-based liveness tracking
    • MCP SDK patched to ^1.26.0 (GHSA-345p-7cg4-v4c7)
    • Rate limiting documentation (reverse proxy recommended for public deployments)
  • v1.0.0 (2026-01-29): Initial authentication implementation
    • API key authentication for HTTP and WebSocket
    • Role-based authorization (admin, agent, read-only)
    • Localhost bypass for development
    • Configuration via environment variables