mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-08 20:57:51 +00:00
Limit password-session cookies to local-owner loopback clients and document device/session-token requirements for remote and multi-user v5 GA access.
360 lines
14 KiB
Markdown
360 lines
14 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
# .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 during development.
|
|
In `NODE_ENV=production`, localhost bypass is not honored for HTTP or WebSocket
|
|
auth, even if an old `.env` file still enables it.
|
|
|
|
### Production
|
|
|
|
For production, configure API keys:
|
|
|
|
```bash
|
|
# .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
|
|
```
|
|
|
|
### Remote/Server Mode
|
|
|
|
Remote access must follow the v5 remote security posture in
|
|
[ADR 0002](architecture/ADR-0002-v5-remote-server-security-posture.md). In
|
|
short: prefer one trusted origin for the web client, `/api`, and `/ws`; keep
|
|
auth enabled; disable localhost bypass outside loopback; use HTTPS, VPN, or a
|
|
trusted tunnel for browser/mobile sessions; and use exact origins instead of
|
|
wildcard CORS.
|
|
|
|
## Authentication Methods
|
|
|
|
Clients can authenticate using any of these methods:
|
|
|
|
### 1. Authorization Header (Recommended)
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer your-api-key" \
|
|
http://localhost:3001/api/tasks
|
|
```
|
|
|
|
### 2. X-API-Key Header
|
|
|
|
```bash
|
|
curl -H "X-API-Key: your-api-key" \
|
|
http://localhost:3001/api/tasks
|
|
```
|
|
|
|
### 3. Query Parameter (WebSocket)
|
|
|
|
```javascript
|
|
const ws = new WebSocket('ws://localhost:3001/ws?api_key=your-api-key');
|
|
```
|
|
|
|
HTTP requests do not accept API keys in query strings. Use headers for HTTP and
|
|
reserve the WebSocket `api_key` query fallback for clients that cannot send auth
|
|
headers during the upgrade.
|
|
|
|
## 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](IDENTITY-RBAC.md).
|
|
|
|
| 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](https://github.com/openclaw/openclaw)
|
|
- **read-only**: Can perform read endpoints, including documented read-like POST
|
|
checks. Suitable for dashboards and monitoring
|
|
|
|
Agent self-service routes are still permission-scoped. Read-like checks such as
|
|
agent routing and permission checks require `agent:read`; approval requests
|
|
require `task:write`; approval review, routing configuration, and permission
|
|
elevation require `admin:manage`.
|
|
|
|
### 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`, `device-session`, 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.
|
|
|
|
Browser password sessions are local-owner only in v5 GA. The server accepts the
|
|
session cookie only on loopback requests with loopback `Host`/`Origin`/`Referer`
|
|
metadata. Remote, server, PWA, and multi-user clients must authenticate with a
|
|
trusted device session or scoped API token so active workspace membership, role,
|
|
revocation, and downgraded scopes are revalidated.
|
|
|
|
The v5 authority surface is tracked in
|
|
[`docs/security/permission-coverage.json`](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.
|
|
|
|
The v5.0 hardening review is recorded in
|
|
[`docs/security/v5-security-review.md`](security/v5-security-review.md),
|
|
including fixed high/critical findings, accepted hardening risks, and the
|
|
password-session local-owner boundary.
|
|
|
|
Release compatibility, stale-client behavior, update channels, and rollback
|
|
limits are tracked in
|
|
[`docs/V5-COMPATIBILITY-AND-RELEASE-POLICY.md`](V5-COMPATIBILITY-AND-RELEASE-POLICY.md).
|
|
Compatibility errors and debug bundles must redact tokens, cookies, private
|
|
keys, local private paths, raw chat content, and task body text.
|
|
|
|
## Configuration Reference
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
| ------------------------------- | ------- | ------------------------------------------------------- |
|
|
| `VERITAS_AUTH_ENABLED` | `true` | Enable/disable authentication |
|
|
| `VERITAS_AUTH_LOCALHOST_BYPASS` | `false` | Allow unauthenticated localhost requests in development |
|
|
| `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
|
|
|
|
```bash
|
|
# Generate a random 32-character key
|
|
openssl rand -base64 32
|
|
```
|
|
|
|
### Using the Built-in Function
|
|
|
|
```typescript
|
|
import { generateApiKey } from './middleware/auth.js';
|
|
const key = generateApiKey('vk'); // e.g., vk_AbCdEf123...
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Auth Status (Unauthenticated)
|
|
|
|
Check the current authentication configuration:
|
|
|
|
```bash
|
|
curl http://localhost:3001/api/auth/status
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"localhostBypass": false,
|
|
"configuredKeys": 2,
|
|
"hasAdminKey": true
|
|
}
|
|
```
|
|
|
|
### Health Check (Unauthenticated)
|
|
|
|
```bash
|
|
curl http://localhost:3001/health
|
|
```
|
|
|
|
## WebSocket Authentication
|
|
|
|
WebSocket connections are authenticated on connect:
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
6. **Keep remote mode explicit** - Binding outside loopback, reverse proxying,
|
|
tunneling, or serving mobile/PWA clients requires auth enabled, localhost
|
|
bypass disabled, exact CORS/WebSocket origins, and redacted diagnostics. See
|
|
[ADR 0002](architecture/ADR-0002-v5-remote-server-security-posture.md).
|
|
|
|
## 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
|